package cn.com.dhcc.turbo.service.exch.filedata;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.ftpserver.usermanager.impl.UserMetadata;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import cn.com.dhcc.app.core.exception.FileSplitException;
import cn.com.dhcc.app.core.exception.NiceException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.handler.compresshandler.CompressResult;
import cn.com.dhcc.app.core.handler.compresshandler.CompressService;
import cn.com.dhcc.app.core.handler.compresshandler.CompressServiceFactory;
import cn.com.dhcc.app.core.handler.compresshandler.CompressStatic.COMPRESS_ALGORITHM;
import cn.com.dhcc.app.core.handler.encrypthandler.EncryptResult;
import cn.com.dhcc.app.core.handler.encrypthandler.EncryptService;
import cn.com.dhcc.app.core.handler.encrypthandler.EncryptServiceFactory;
import cn.com.dhcc.app.core.handler.encrypthandler.EncryptStatic.ENCRYPT_ALGORITHM;
import cn.com.dhcc.app.core.handler.filesplithandler.FileSplitService;
import cn.com.dhcc.app.core.handler.filesplithandler.FileSplitServiceFactory;
import cn.com.dhcc.app.core.handler.filesplithandler.FileSplitStatic;
import cn.com.dhcc.app.core.handler.filesplithandler.FileSplitStatic.FILESPLIT_ALGORITHM;
import cn.com.dhcc.app.core.handler.filesplithandler.Packet;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.service.Log.LOGTYPE;
import cn.com.dhcc.app.core.util.BeanMapper;
import cn.com.dhcc.app.core.util.CollectionUtil;
import cn.com.dhcc.app.core.util.DateUtil;
import cn.com.dhcc.app.core.util.JsonUtil;
import cn.com.dhcc.app.core.util.NetUtil;
import cn.com.dhcc.app.core.util.Status;
import cn.com.dhcc.app.core.util.UUIDGenerator;
import cn.com.dhcc.app.core.util.XstreamUtil;
import cn.com.dhcc.app.pub.core.consts.AppConst;
import cn.com.dhcc.app.pub.core.consts.AppConst.ExchDataType;
import cn.com.dhcc.app.pub.core.consts.AppConst.PostheadStatus;
import cn.com.dhcc.app.pub.core.consts.AppIocBean;
import cn.com.dhcc.app.pub.core.consts.KernelParam;
import cn.com.dhcc.app.pub.core.consts.NodeInfoParam;
import cn.com.dhcc.app.pub.core.service.TurboFtpClientFactory;
import cn.com.dhcc.app.pub.core.tag.AppTagEl;
import cn.com.dhcc.app.pub.core.util.FtpUtil;
import cn.com.dhcc.app.pub.core.util.TurboUtil;
import cn.com.dhcc.app.pub.core.util.ZipUtil;
import cn.com.dhcc.turbo.entity.api.OrderResp;
import cn.com.dhcc.turbo.entity.api.Posthead;
import cn.com.dhcc.turbo.entity.api.ProcessInfo;
import cn.com.dhcc.turbo.entity.api.Processes;
import cn.com.dhcc.turbo.entity.api.RouteEntry;
import cn.com.dhcc.turbo.entity.api.RouteLog;
import cn.com.dhcc.turbo.entity.api.SendResp;
import cn.com.dhcc.turbo.entity.exch.CrossNetTmpFileData;
import cn.com.dhcc.turbo.entity.exch.ExchErrorLog;
import cn.com.dhcc.turbo.entity.exch.FileData;
import cn.com.dhcc.turbo.entity.exch.RecvFileData;
import cn.com.dhcc.turbo.entity.exch.SendFileData;
import cn.com.dhcc.turbo.entity.registry.AdapterBase;
import cn.com.dhcc.turbo.entity.registry.AdapterInfo;
import cn.com.dhcc.turbo.entity.registry.FtpUser;
import cn.com.dhcc.turbo.entity.registry.NodeInfo;
import cn.com.dhcc.turbo.service.exch.ApiUserAuthService;
import cn.com.dhcc.turbo.service.exch.DistributedNodeInfoService;
import cn.com.dhcc.turbo.service.exch.ExchErrorLogService;
import cn.com.dhcc.turbo.service.exch.HttpClientUserInfo;
import cn.com.dhcc.turbo.service.exch.HttpDataExchRecvService;
import cn.com.dhcc.turbo.service.exch.TurboCompressFilter;
import cn.com.dhcc.turbo.service.exch.TurboEncryptFilter;
import cn.com.dhcc.turbo.service.exch.cmdata.CarvedDiscsDataService;
import cn.com.dhcc.turbo.service.exch.exhmgr.FtpUserService;
import cn.com.dhcc.turbo.service.exch.expired.ExpiredStrategy;
import cn.com.dhcc.turbo.service.exch.filedata.validator.FileDataMessageValidator;
import cn.com.dhcc.turbo.service.registry.BaseInfoService;
import cn.com.dhcc.turbo.service.registry.DataCategoryService;
import cn.com.dhcc.turbo.service.registry.vo.PipeLineFtp;
import cn.com.dhcc.turbo.service.test.NodeExchTestService;

/**
 * 通用数据发送生命周期
 * 
 * 数据交换路线
 * 
 * 发送节点--接收节点远程落地(路由1)--接收节点通知接收适配器(路由2)-- 发送节点回执 (路由3)
 * 
 * 发送节点--接收节点远程落地(路由1)--网闸节点刻盘(路由2)
 * 
 * 发送节点--网闸节点存储(路由1)--网闸节点发送到网闸(路由2)
 * 
 * 
 * 
 * 
 * 
 */
@Service("fileDataExchageLifecycle")
public class FileDataExchageLifecycleImp implements FileDataExchageLifecycle {
	@SuppressWarnings("deprecation")
	private Logger logger = Log.getDetachLogger(LOGTYPE.QUARTZJOB);
	private static FileSplitService fileSplit = FileSplitServiceFactory.createFileSplitService(FILESPLIT_ALGORITHM.SIMPLE);

	private static final int fileDeleteTime=7;//文件删除的时间，单位天
	//用户上传到ftp服务器的xml目录。该目录是相对目录,存在用户自身目录下
	private static final String uploadxmlDir = AppConst.FILEDATA_UPLOADXML_DIR;
	//用户上传到ftp服务器的文件目录。该目录是相对目录,存在用户自身目录下
	private static final String uploadmetadataDir = AppConst.FILEDATA_UPLOADMETADATA_DIR;
	//插入数据库成功后xml响应的目录。该目录是相对目录，存在用户自身目录下
	private static final String successxmlDir = AppConst.FILEDATA_SUCCESSXML_DIR;
	//插入数据库失败后xml响应的目录。该目录是相对目录，存在用户自身目录下
	private static final String failxmlDir =  AppConst.FILEDATA_FAILXML_DIR;
	//接收节点公共xml目录。admin目录下
	private static final String recvxmlDir =AppConst.FILEDATA_RECVXML_DIR;
	//接收节点公共文件目录。admin目录下
	private static final String recvmetadataDir =AppConst.FILEDATA_RECVMETADATA_DIR;
	
	//接收节点公共文件目录。admin目录下
	private static final String crossmetadataDir = AppConst.FILEDATA_CROSSMETADATA_DIR;
	
	//接收节点公共文件目录。admin目录下
	private static final String crossxmlDir =AppConst.FILEDATA_CROSSXML_DIR;
	
	//接收xml头文件目录。admin目录下
	private static final String remoterespDir =AppConst.FILEDATA_REMOTERESP_DIR;
	//接收xml头文件目录。admin目录下
	private static final String localrespDir = AppConst.FILEDATA_LOCALRESP_DIR;

	//解析头文件成功后，给发送者的响应
	private static final String globalToSendrespDir =AppConst.FILEDATA_GLOBALTOSENDRESP_DIR;
	//解析头文件成功后，给接收者的响应
	private static final String globalToRecvrespDir =AppConst.FILEDATA_GLOBALTORECVRESP_DIR;
	//大文件存放的公共目录。
	private static final String globalUploadmetadataDir =AppConst.FILEDATA_GLOBALUPLOADMETADATA_DIR;
	
	private static final String inIp = NodeInfoParam.GAP_PARAM.IP;// FTP服务器地址
	private static final int inPort =NodeInfoParam.GAP_PARAM.Port;// FTP服务器端口
	private static final String inUserName = NodeInfoParam.GAP_PARAM.UserName;// 登录FTP服务器账号
	private static final String inPassword = NodeInfoParam.GAP_PARAM.Password;// 登陆FTP服务器密码
	private static final String inOutput = NodeInfoParam.GAP_PARAM.Home; // 下载文件目录  
	private static final String localFtpPut = AppConst.APP_GAP_FTP_INNER_LOCALFTPPUT; // 下载文件本地临时目录  
	


	/**
	 * 批次处理的最大数量
	 */
	private static final int BATCH_NUM=30;
	
	@SuppressWarnings("unused")
	private static final int CHECK_NUM=3;//检索FTP服务器上同名文件的次数.
	
	
	@Autowired
	private DataCategoryService dataCategoryService;
	@Autowired
	private ApiUserAuthService apiUserAuthService;
	
	@Autowired
	@Qualifier("fileDataPostheadValidator")
	private FileDataMessageValidator validator;
	@Autowired
	private SendFileDataService sendFileDataService;
	@Autowired
	private RecvFileDataService recvFileDataService;
	@Autowired
	private FtpUserService ftpUserService;
	@Autowired
	private ExchErrorLogService exchErrorLogService;
	@Autowired
	private BaseInfoService baseInfoService;
	@Autowired
	private DistributedNodeInfoService  distributedNodeInfoService;
	@Autowired
	private CarvedDiscsDataService carvedDiscsDataService;
	
	@Autowired
    private WebServiceContext servicecontext;

	
	@Autowired
	@Qualifier(AppIocBean.TIMEOUT_EXPIRED_STRATEGY_BEAN)
	private ExpiredStrategy timeoutExpiredStrategy;
	@Autowired
	private CrossNetTmpFileDataService crossNetTmpFileDataService;
	
	

	
	@Override
	public Status validate(File posthead) {
		return validator.validate(posthead);
	}
    
	/**
	 * 判断文件file是否有临时文件
	 * @param list
	 * @param file
	 * @return
	 */
	private boolean existTmpFile(File[] list,File file){
		boolean flag=false;
		for (File file2 : list) {
			if (!file2.getName().equals(file.getName()) && file2.getName().startsWith(file.getName())) {
				return true;
			}
		}
		return flag;
	}
	

	

	/**
	 * 打印文件数组
	 * @param fs
	 */
	private String fileArrayNames(File[] fs){
		if (fs==null || fs.length<=0) {
			return null;
		}
		StringBuilder sb=new StringBuilder();
		for (int i = 0; i < fs.length; i++) {
			File file = fs[i];
			if(i<fs.length-1){
				sb.append(file.getName()+",");
			}else{
				sb.append(file.getName());
			}
		}
		return sb.toString();
	}
	/**
	 * 第1步
	 * 信息入库，数据报文XML转移至公共目录
	 * 入库前进行数据校验
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public String  checkToDB(String postname,String authCode,String metadata,String fromAdapter,List<String> fileItems) {
		String msg = "";
		Status status = Status.getInstance();
		NodeInfo localNode=null;
		SendResp sendResp=new SendResp();
		String groupId= postname.substring(0, postname.lastIndexOf(".xml"));
		File filexml=null;
		try {
			localNode=baseInfoService.getCurrentNodeInfo();
			FtpUser user = ftpUserService.get(fromAdapter);
			if (user==null) {
				logger.info("发送系统"+fromAdapter+"没有对应的用户");
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage("发送系统"+fromAdapter+"没有对应的用户");
				return XstreamUtil.toXml(sendResp);
			}
			
			String home = user.getHomedirectory();
			File dir = new File(home, uploadxmlDir);
			if (!dir.isDirectory()) {
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage(dir + "不是一个有效的文件夹");
				return XstreamUtil.toXml(sendResp);
			}
			//一个filexml文件就是一次请求
		    filexml=new File(dir,postname);
			if (filexml == null || !checkFilename(filexml) || !filexml.exists()) {
				logger.info(home + "下没有文件需要解析");
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage("文件:"+postname+"不存在");
				return XstreamUtil.toXml(sendResp);
			
			}
			List<OrderResp> orderRespList=new ArrayList<OrderResp>();//子消息响应集合
			String context = FileUtils.readFileToString(filexml);
			String filexmlname = filexml.getName();
			Date filedate = new Date(filexml.lastModified());
			Date now = new Date();
			//验证文件的有效性
			status = validator.validate(filexml);
			if (!status.isSuccess() ) {
				//解析失败。返回error响应,并把文件删除
				if (filexml.delete()) {
					//发送响应
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(status.getMsg());
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
						
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.BAD_REQUEST.value());
					exchErrorLog.setMessage("解析文件失败");
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(status.getMsg());
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
					logger.error(status.getMsg());
				}
				return XstreamUtil.toXml(sendResp);
			}
			
			
			
			//获取头文件信息
			Posthead posthead = (Posthead) status.getData();
			
			//验证授权码的有效性
			MessageContext ctx=servicecontext.getMessageContext();
			HttpServletRequest request = (HttpServletRequest) ctx
	                .get(AbstractHTTPDestination.HTTP_REQUEST);
	        String ip = NetUtil.getRemoteIp(request);
	        HttpClientUserInfo webClient=new HttpClientUserInfo();
			webClient.setAdapterCode(posthead.getFrom().getAdaptorcode());
			webClient.setAuthCode(authCode);
			UserMetadata userMetadata=new UserMetadata();
			userMetadata.setInetAddress(InetAddress.getByName(ip));
			webClient.setUserMetadata(userMetadata);
			if (KernelParam.authValidate && !apiUserAuthService.isAdapterAuthCodeOkForHttp(webClient)) {
				//验证失败
				if (filexml.delete()) {
					msg="授权码"+authCode+"不是适配器"+posthead.getFrom().getAdaptorcode()+"的授权码";
					//发送响应
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(msg);
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
						
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.BAD_REQUEST.value());
					exchErrorLog.setMessage("验证失败");
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(msg);
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
					logger.error(msg);
				}
				return XstreamUtil.toXml(sendResp);
			}
			
			
			List<RouteEntry> toList = posthead.getToList();
			RouteEntry from = posthead.getFrom();
			//针对一个xml文件的全部响应信息
			List<SendFileData> fileDataList = new ArrayList<SendFileData>();

			List<String> attachments = posthead.getAttachments().getAttachment();
			String filepaths = "";
			String storepaths = "";
			long size = 0;
			File uploadmetadir = new File(home, uploadmetadataDir);
			File globaluploalpath = new File(globalUploadmetadataDir, AppConst.dFormat.format(now));
			boolean renamefile = false;
			String renamemessage = "";
			
			//压缩处理
			CompressService compressService = CompressServiceFactory.createCompressService(COMPRESS_ALGORITHM.JAVA_GZIP);
			//加密处理
			//解密处理
			EncryptService encryptService = EncryptServiceFactory.createEncryptService(ENCRYPT_ALGORITHM.DES);
			
			Processes pes=new Processes();//处理文件
			List<ProcessInfo> processInfos=new ArrayList<ProcessInfo>();
			for (int i = 0; i < attachments.size(); i++) {
				String attachment = attachments.get(i);
				while (attachment.indexOf("/") == 0 || attachment.indexOf("\\") == 0) {
					attachment = attachment.substring(1);//去掉首字母的"/"
				}
				File file = new File(uploadmetadir, attachments.get(i));
				size += file.length();
				String filename = attachments.get(i);
				int j = filename.lastIndexOf(".");
				String suffix = "";
				if (j != -1) {
					suffix = filename.substring(j);
				}
				//压缩处理
				CompressResult<String> result = compressService.compress(file,new TurboCompressFilter(ExchDataType.FILE_DATA, null),true);
				ProcessInfo pi=new ProcessInfo();
				String compress="0";
				if (result.isCommpressed()) {
					compress="1";
					file=new File(result.getCommpressResultObj());//文件指向压缩文件
					pi.setCompressfile(file.getName());
				}
				pi.setCompress(compress);
				
				//加密处理dataCategoryEncryptEnabbled
				boolean isEncrypt=dataCategoryService.isEncode(posthead.getFrom().getDatatype());//根据数据分类判断是否加密处理
				String seed=encryptService.randomSeed(posthead.getFrom().getNodecode()+posthead.getFrom().getAdaptorcode());//加密秘钥
				EncryptResult<String> sresult=  encryptService.encryptFile(seed,file.getAbsolutePath(),new TurboEncryptFilter(ExchDataType.FILE_DATA, null,isEncrypt),true);
				String encrypt="0";//加密标志
				if (sresult.isEncrypted()) {
					encrypt="1";
					file=new File(sresult.getEncryptResultObj());//文件指向加密文件
					pi.setEncryptfile(file.getName());
				}
				pi.setEncrypt(encrypt);
				
				processInfos.add(pi);
				
				
				String uuid = UUIDGenerator.getUUID();
				if (globaluploalpath.exists() || globaluploalpath.mkdirs()) {
					String newfilename = uuid + suffix;
					if (i == 0) {
						filepaths += attachment;
						storepaths += newfilename;
					} else {
						filepaths += ";" + attachment;
						storepaths += ";" + newfilename;
					}
					File newfile = new File(globaluploalpath, newfilename);
					renamefile = file.renameTo(newfile);
					if (!renamefile) {
						renamemessage = file.getAbsolutePath() + "目录下的文件" + file.getName() + "重命名为"
								+ newfile.getAbsolutePath() + "目录下的文件" + newfile.getName() + "失败了";
						break;
					}
				}
			}
			if (!renamefile) {
				if (filexml.delete()) {//附件处理出错
					String message = "重命名文件失败";
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(message);
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.INTERNAL_SERVER_ERROR.value());
					exchErrorLog.setMessage(message);
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(renamemessage);
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
				}
				return XstreamUtil.toXml(sendResp);
			}

			pes.setProcess(processInfos);
			posthead.setProcesses(pes);
			for (RouteEntry to : toList) {
				OrderResp orderResp = new OrderResp();//针对子消息的响应
				String respXml = "";//针对一个to的响应xml
				String id =  UUIDGenerator.getUUID();
//							String msgType=null;
				msg = "数据接收成功";
				if (toList.size() == 1) {
					id = groupId;
//								msgType = AppConst.MsgType.SINGLE_MSG.value();
				}else{
//								msgType = AppConst.MsgType.SUB_MSG.value();
				}
				orderResp.setOrderId(id);
				orderResp.setAdaptorcode(from.getAdaptorcode());
				orderRespList.add(orderResp);
				respXml = XstreamUtil.toXml(orderResp);
				
				SendFileData sendfileData = new SendFileData();
				sendfileData.setOrderId(id);
				sendfileData.setGroupId(groupId);
				sendfileData.setSendNodecode(from.getNodecode());
				sendfileData.setSendBusicode(from.getDatatype());
				sendfileData.setSendAdaptorcode(from.getAdaptorcode());
				sendfileData.setRecvNodecode(to.getNodecode());
				sendfileData.setRecvAdaptorcode(from.getAdaptorcode());
				sendfileData.setPosthead(XstreamUtil.toXml(posthead));
				sendfileData.setResp(respXml);
				sendfileData.setSendStatus(AppConst.SendStatus.READY.value());
				sendfileData.setNotifyStatus(AppConst.NotifyStatus.READY.value());
				sendfileData.setPriority(AppConst.Priority.NORMAL.value());
				sendfileData.setPipeline(AppConst.FTP);
				//                            fileData.setIp(ip);
				
				sendfileData.setCreated(now);
				sendfileData.setFilehome(globaluploalpath.getAbsolutePath());
				sendfileData.setFilepaths(filepaths);
				sendfileData.setStorepaths(storepaths);
				sendfileData.setFilesize(size);
				if (from.getNodecode().substring(0, 6).equals(to.getNodecode().substring(0,6))) {//取前六位看是否是跨节点传输
					sendfileData.setCrossNode("0");
				}else{
					sendfileData.setCrossNode("1");
				}
				
				if (from.getNodecode().substring(6, 7).equals(to.getNodecode().substring(6, 7))) {
					sendfileData.setCrossNet("0");
					sendfileData.setThroughGap("0");//不需要走网闸
					sendfileData.setThroughGap("0");//不需需要走网闸
				}else{
					 if (AppTagEl.isInnerNet(from.getNodecode().substring(6, 7)) && !AppTagEl.isInnerNet(to.getNodecode())) {//from为内网 to为外网
						 sendfileData.setCrossNet("1");
					 }else{//from为外网，to为内网 需要走网闸
						 sendfileData.setCrossNet("2");
						 String gapNode=baseInfoService.getGapNode(localNode);
						 
						 if (gapNode!=null) {
							 sendfileData.setThroughGap("1");//需要走网闸
							 sendfileData.setOutGapNodeCode(gapNode);
						 }else{
							 sendfileData.setThroughGap("2");//需要刻盘
							 sendfileData.setOutGapNodeCode(null);
						 }
					}
				}
				sendfileData.setAuditPerson(from.getAuditor());//审核人
				sendfileData.setTrig(from.getSendTime());
				sendfileData.setMetaData(metadata);
				sendfileData.setFileItems(JsonUtil.toJson(fileItems));
				RouteLog.setLocalStore(sendfileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
				//添加记录
				fileDataList.add(sendfileData);
				//we just assume this is always success...
			}
			sendFileDataService.insertBatch(fileDataList);//存数据库
			String filename = filexml.getName();
			if (filexml.delete()) {
				sendResp.setOrderRespList(orderRespList);
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.OK.value());
				sendResp.setMessage("数据入库成功");
				sendResp.setDate(AppConst.dtFormat.format(new Date()));
				msg = "数据接收成功";
				status.setSuccess(true);
				status.setMsg(msg);
				File file = new File(new File(home, successxmlDir), filename);
				File parent = file.getParentFile();
				if (parent.exists() || parent.mkdirs()) {
					XstreamUtil.toXmlfile(sendResp, file);
				}
				return XstreamUtil.toXml(sendResp);
			}//删除文件
		} catch (Exception e) {
			msg = "检查本地FTP文件失败，" + e.fillInStackTrace();
			logger.error(msg, e);
			sendResp.setGroupId(groupId);
			sendResp.setStatus(PostheadStatus.INTERNAL_SERVER_ERROR.value());
			sendResp.setMessage("文件:"+postname+"不存在");
			
			//删除该文件
			if (filexml.delete()) {
				logger.info("文件"+filexml.getAbsolutePath()+"删除成功");
			}else{
				logger.info("文件"+filexml.getAbsolutePath()+"删除失败");
			}
			try {
				return XstreamUtil.toXml(sendResp);
			} catch (Exception e1) {
				logger.error(e);
			}
		}
		return null;
	}
	
	/**
	 * 第1步
	 * 信息入库，数据报文XML转移至公共目录
	 * 入库前进行数据校验
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public String  checkToDB(String postname,String authCode,String metadata,String fromAdapter,String remoteIp,List<String> fileItems) {
		String msg = "";
		Status status = Status.getInstance();
		NodeInfo localNode=null;
		SendResp sendResp=new SendResp();
		String groupId= postname.substring(0, postname.lastIndexOf(".xml"));
		File filexml=null;
		try {
			localNode=baseInfoService.getCurrentNodeInfo();
			FtpUser user = ftpUserService.get(fromAdapter);
			if (user==null) {
				logger.info("发送系统"+fromAdapter+"没有对应的用户");
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage("发送系统"+fromAdapter+"没有对应的用户");
				return XstreamUtil.toXml(sendResp);
			}
			
			String home = user.getHomedirectory();
			File dir = new File(home, uploadxmlDir);
			if (!dir.isDirectory()) {
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage(dir + "不是一个有效的文件夹");
				return XstreamUtil.toXml(sendResp);
			}
					
			//一个filexml文件就是一次请求
		    filexml=new File(dir,postname);
			if (filexml == null || !checkFilename(filexml) || !filexml.exists()) {
				logger.info(home + "下没有文件需要解析");
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
				sendResp.setMessage("文件:"+postname+"不存在");
				return XstreamUtil.toXml(sendResp);
			
			}
			List<OrderResp> orderRespList=new ArrayList<OrderResp>();//子消息响应集合
			String context = FileUtils.readFileToString(filexml);
			String filexmlname = filexml.getName();
			Date filedate = new Date(filexml.lastModified());
			Date now = new Date();
			//验证文件的有效性
			status = validator.validate(filexml);
			if (!status.isSuccess() ) {
				//解析失败。返回error响应,并把文件删除
				if (filexml.delete()) {
					//发送响应
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(status.getMsg());
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
						
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.BAD_REQUEST.value());
					exchErrorLog.setMessage("解析文件失败");
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(status.getMsg());
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
					logger.error(status.getMsg());
				}
				return XstreamUtil.toXml(sendResp);
			}
			
			
			
			//获取头文件信息
			Posthead posthead = (Posthead) status.getData();
			
			//验证授权码的有效性
			/*MessageContext ctx=servicecontext.getMessageContext();
			HttpServletRequest request = (HttpServletRequest) ctx
	                .get(AbstractHTTPDestination.HTTP_REQUEST);*/
	     //   String ip = request.getRemoteAddr();
			HttpClientUserInfo webClient=new HttpClientUserInfo();
			webClient.setAdapterCode(posthead.getFrom().getAdaptorcode());
			webClient.setAuthCode(authCode);
			UserMetadata userMetadata=new UserMetadata();
			userMetadata.setInetAddress(InetAddress.getByName(remoteIp));
			webClient.setUserMetadata(userMetadata);
			if (KernelParam.authValidate && !apiUserAuthService.isAdapterAuthCodeOkForHttp(webClient)) {
				//验证失败
				if (filexml.delete()) {
					msg="授权码"+authCode+"不是适配器"+posthead.getFrom().getAdaptorcode()+"的授权码";
					//发送响应
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(msg);
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
						
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.BAD_REQUEST.value());
					exchErrorLog.setMessage("验证失败");
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(msg);
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
					logger.error(msg);
				}
				return XstreamUtil.toXml(sendResp);
			}
			
			
			List<RouteEntry> toList = posthead.getToList();
			RouteEntry from = posthead.getFrom();
			AdapterBase adapterBase=baseInfoService.getAdapterBase(from.getAdaptorcode());
			//针对一个xml文件的全部响应信息
			List<SendFileData> fileDataList = new ArrayList<SendFileData>();

			List<String> attachments = posthead.getAttachments().getAttachment();
			String filepaths = "";
			String storepaths = "";
			long size = 0;
			File uploadmetadir = new File(home, uploadmetadataDir);
			File globaluploalpath = new File(globalUploadmetadataDir, AppConst.dFormat.format(now));
			boolean renamefile = false;
			String renamemessage = "";
			
			//压缩处理
			CompressService compressService = CompressServiceFactory.createCompressService(COMPRESS_ALGORITHM.JAVA_GZIP);
			//加密处理
			//解密处理
			EncryptService encryptService = EncryptServiceFactory.createEncryptService(ENCRYPT_ALGORITHM.DES);
			
			Processes pes=new Processes();//处理文件
			List<ProcessInfo> processInfos=new ArrayList<ProcessInfo>();
			for (int i = 0; i < attachments.size(); i++) {
				String attachment = attachments.get(i);
				while (attachment.indexOf("/") == 0 || attachment.indexOf("\\") == 0) {
					attachment = attachment.substring(1);//去掉首字母的"/"
				}
				File file = new File(uploadmetadir, attachments.get(i));
				size += file.length();
				String filename = attachments.get(i);
				int j = filename.lastIndexOf(".");
				String suffix = "";
				if (j != -1) {
					suffix = filename.substring(j);
				}
				//压缩处理
				CompressResult<String> result = compressService.compress(file,new TurboCompressFilter(ExchDataType.FILE_DATA, null),true);
				ProcessInfo pi=new ProcessInfo();
				String compress="0";
				if (result.isCommpressed()) {
					compress="1";
					file=new File(result.getCommpressResultObj());//文件指向压缩文件
					pi.setCompressfile(file.getName());
				}
				pi.setCompress(compress);
				
				//加密处理dataCategoryEncryptEnabbled
				boolean isEncrypt=dataCategoryService.isEncode(posthead.getFrom().getDatatype());//根据数据分类判断是否加密处理
				String seed=encryptService.randomSeed(posthead.getFrom().getNodecode()+posthead.getFrom().getAdaptorcode());//加密秘钥
				EncryptResult<String> sresult=  encryptService.encryptFile(seed,file.getAbsolutePath(),new TurboEncryptFilter(ExchDataType.FILE_DATA, null,isEncrypt),true);
				String encrypt="0";//加密标志
				if (sresult.isEncrypted()) {
					encrypt="1";
					file=new File(sresult.getEncryptResultObj());//文件指向加密文件
					pi.setEncryptfile(file.getName());
				}
				pi.setEncrypt(encrypt);
				
				processInfos.add(pi);
				
				
				String uuid = UUIDGenerator.getUUID();
				if (globaluploalpath.exists() || globaluploalpath.mkdirs()) {
					String newfilename = uuid + suffix;
					if (i == 0) {
						filepaths += attachment;
						storepaths += newfilename;
					} else {
						filepaths += ";" + attachment;
						storepaths += ";" + newfilename;
					}
					File newfile = new File(globaluploalpath, newfilename);
					renamefile = file.renameTo(newfile);
					if (!renamefile) {
						renamemessage = file.getAbsolutePath() + "目录下的文件" + file.getName() + "重命名为"
								+ newfile.getAbsolutePath() + "目录下的文件" + newfile.getName() + "失败了";
						break;
					}
				}
			}
			if (!renamefile) {
				if (filexml.delete()) {//附件处理出错
					String message = "重命名文件失败";
					sendResp.setGroupId(groupId);
					sendResp.setStatus(PostheadStatus.BAD_REQUEST.value());
					sendResp.setMessage(message);
					sendResp.setDate(AppConst.dtFormat.format(new Date()));
					File file = new File(new File(home, failxmlDir), filexmlname);
					File parent = file.getParentFile();
					if (parent.exists() || parent.mkdirs()) {
						XstreamUtil.toXmlfile(sendResp, file);
					}
					ExchErrorLog exchErrorLog = new ExchErrorLog();
					exchErrorLog.setId(UUIDGenerator.getUUID());
					exchErrorLog.setStatus(AppConst.PostheadStatus.INTERNAL_SERVER_ERROR.value());
					exchErrorLog.setMessage(message);
					exchErrorLog.setCreated(filedate);
					exchErrorLog.setErrstack(renamemessage);
					exchErrorLog.setFilename(filexmlname);
					exchErrorLog.setSyscode(user.getUserid());
					exchErrorLog.setPosthead(context);
					exchErrorLog.setType(AppConst.ExchDataType.FILE_DATA.value());
					exchErrorLogService.insert(exchErrorLog);
				}
				return XstreamUtil.toXml(sendResp);
			}

			pes.setProcess(processInfos);
			posthead.setProcesses(pes);
			for (RouteEntry to : toList) {
				OrderResp orderResp = new OrderResp();//针对子消息的响应
				String respXml = "";//针对一个to的响应xml
				String id =  UUIDGenerator.getUUID();
//							String msgType=null;
				msg = "数据接收成功";
				if (toList.size() == 1) {
					id = groupId;
//								msgType = AppConst.MsgType.SINGLE_MSG.value();
				}else{
//								msgType = AppConst.MsgType.SUB_MSG.value();
				}
				orderResp.setOrderId(id);
				orderResp.setAdaptorcode(from.getAdaptorcode());
				orderRespList.add(orderResp);
				respXml = XstreamUtil.toXml(orderResp);
				
				SendFileData sendfileData = new SendFileData();
				sendfileData.setOrderId(id);
				sendfileData.setGroupId(groupId);
				sendfileData.setSendNodecode(from.getNodecode());
				sendfileData.setSendBusicode(adapterBase.getDataCode());
				sendfileData.setSendAdaptorcode(from.getAdaptorcode());
				sendfileData.setRecvNodecode(to.getNodecode());
				sendfileData.setRecvAdaptorcode(from.getAdaptorcode());
				sendfileData.setPosthead(XstreamUtil.toXml(posthead));
				sendfileData.setResp(respXml);
				sendfileData.setSendStatus(AppConst.SendStatus.READY.value());
				sendfileData.setNotifyStatus(AppConst.NotifyStatus.READY.value());
				sendfileData.setPriority(AppConst.Priority.NORMAL.value());
				sendfileData.setPipeline(AppConst.FTP);
				//                            fileData.setIp(ip);
				sendfileData.setCreated(now);
				sendfileData.setFilehome(globaluploalpath.getAbsolutePath());
				sendfileData.setFilepaths(filepaths);
				sendfileData.setStorepaths(storepaths);
				sendfileData.setFilesize(size);
				if (from.getNodecode().substring(0, 6).equals(to.getNodecode().substring(0,6))) {//取前六位看是否是跨节点传输
					sendfileData.setCrossNode("0");
				}else{
					sendfileData.setCrossNode("1");
				}
				
				if (from.getNodecode().substring(6, 7).equals(to.getNodecode().substring(6, 7))) {
					sendfileData.setCrossNet("0");
					sendfileData.setThroughGap("0");//不需要走网闸
					sendfileData.setThroughGap("0");//不需需要走网闸
				}else{
					 if (AppTagEl.isInnerNet(from.getNodecode().substring(6, 7)) && !AppTagEl.isInnerNet(to.getNodecode())) {//from为内网 to为外网
						 sendfileData.setCrossNet("1");
					 }else{//from为外网，to为内网 需要走网闸
						 sendfileData.setCrossNet("2");
						 String gapNode=baseInfoService.getGapNode(localNode);
						 
						 if (gapNode!=null) {
							 sendfileData.setThroughGap("1");//需要走网闸
							 sendfileData.setOutGapNodeCode(gapNode);
						 }else{
							 sendfileData.setThroughGap("2");//需要刻盘
							 sendfileData.setOutGapNodeCode(null);
						 }
					}
				}
				sendfileData.setAuditPerson(from.getAuditor());//审核人
				sendfileData.setTrig(from.getSendTime());
				sendfileData.setMetaData(metadata);
				sendfileData.setFileItems(JsonUtil.toJson(fileItems));
				RouteLog.setLocalStore(sendfileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
				//添加记录
				fileDataList.add(sendfileData);
				//we just assume this is always success...
			}
			sendFileDataService.insertBatch(fileDataList);//存数据库
			String filename = filexml.getName();
			if (filexml.delete()) {
				sendResp.setOrderRespList(orderRespList);
				sendResp.setGroupId(groupId);
				sendResp.setStatus(PostheadStatus.OK.value());
				sendResp.setMessage("数据入库成功");
				sendResp.setDate(AppConst.dtFormat.format(new Date()));
				msg = "数据接收成功";
				status.setSuccess(true);
				status.setMsg(msg);
				File file = new File(new File(home, successxmlDir), filename);
				File parent = file.getParentFile();
				if (parent.exists() || parent.mkdirs()) {
					XstreamUtil.toXmlfile(sendResp, file);
				}
				logger.info("--checkDB,postname["+postname+"],返回值"+sendResp);
				return XstreamUtil.toXml(sendResp);
			}else{//删除文件
				logger.info("--checkDB,postname["+postname+"],返回值"+sendResp+",filexml["+filexml+"]删除失败了");
			}
		} catch (Exception e) {
			msg = "检查本地FTP文件失败，" + e.fillInStackTrace();
			logger.error("postname["+postname+"],"+msg, e);
			sendResp.setGroupId(groupId);
			sendResp.setStatus(PostheadStatus.INTERNAL_SERVER_ERROR.value());
			sendResp.setMessage("文件:"+postname+"不存在");
			
			//删除该文件
			if (filexml.delete()) {
				logger.info("文件"+filexml.getAbsolutePath()+"删除成功");
			}else{
				logger.info("文件"+filexml.getAbsolutePath()+"删除失败");
			}
			try {
				return XstreamUtil.toXml(sendResp);
			} catch (Exception e1) {
				logger.error(e);
			}
		}
		return null;
	}
	/**
	 * 将posthead格式化
	 * @param posthead
	 */
	private Posthead formatt(Posthead posthead,String nodecode,String adaptercode){
		Posthead newPosthead=posthead;
		List<RouteEntry> toList=posthead.getToList();
		List<RouteEntry> toNewList=new ArrayList<RouteEntry>();
		for (RouteEntry routeEntry : toList) {
			if (routeEntry.getNodecode().equals(nodecode)) {
				toNewList.add(routeEntry);
			}
		}
		newPosthead.setToList(toNewList);
		return newPosthead;
		
	}

	/**
	 * 本节点既是发送节点，又是接受节点
	 */
	@Override
	public Status sendDataLocalSys() {
		String msg = "";
		Status status = Status.getInstance();
		List<SendFileData> successDataList = new ArrayList<SendFileData>(); //往管道发送成功的数据
		List<SendFileData> resendDataList = new ArrayList<SendFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> resendDataList1 = new ArrayList<SendFileData>();  //刻盘需要待重发的
		List<SendFileData> failDataList = new ArrayList<SendFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			//获取待发送的数据
			List<SendFileData> unsendDataList = sendFileDataService.getUnsentLocalSysList();
			if (CollectionUtil.hasElement(unsendDataList)) {
				for (SendFileData fileData : unsendDataList) {
					msg = "发送到本地系统成功";
					fileData.setSendStatus(AppConst.SendStatus.LOCAL_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setRemoteSys(fileData, AppConst.YES, msg, AppConst.dtFormat.format(new Date()));
				}
				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateLocalSendStatus(unsendDataList, AppConst.SendStatus.LOCAL_SENDING.value());
				if (!status.isSuccess()) {
					msg = "发送到本地系统失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}
				
				/********先压缩，后加密   最后处理先解密 再解压缩**************/
				//获取解压缩处理的service
				CompressService compressService = CompressServiceFactory.createCompressService(COMPRESS_ALGORITHM.JAVA_GZIP);
				//TODO 获取加密处理service
				//解密处理
				EncryptService encryptService = EncryptServiceFactory.createEncryptService(ENCRYPT_ALGORITHM.DES);
				
				//循环处理发送到本地系统的消息
				for (SendFileData fileData : unsendDataList) {
					String[] attachements = fileData.getFilepaths().split(";");
					String[] storepaths = fileData.getStorepaths().split(";");
					
					//获取接受节点信息，并创建接受的文件夹
					String to = fileData.getRecvAdaptorcode();
					FtpUser touser = ftpUserService.get(to);
					
					//创建两级目录 xxx(节点)/xxx（适配器）
					File recvmetadir = new File(new File(touser.getHomedirectory(), recvmetadataDir),
							fileData.getSendNodecode());
//					recvmetadir=new File(recvmetadir,to);
					
					
					//从头文件获取解压缩信息
					List<ProcessInfo> list=XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getProcesses().getProcess();
					
					//文件处理
					for (int i=0;i<storepaths.length;i++) {
						String filename=storepaths[i];
						File fromfile = new File(fileData.getFilehome(), filename);
						
						File fileto = new File(recvmetadir, attachements[i]);
						File parent = fileto.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							FileUtils.copyFile(fromfile, fileto);//复制文件
							
							//对fileto进行解密和解压缩
                            //解密处理
							String encrypt=list.get(0).getEncrypt();
							if (encrypt.equals("1")) {//解密
								String seed=encryptService.getSeed(XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getFrom().getNodecode()+XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getFrom().getAdaptorcode());
								File encryptFile=new File(fileto.getParentFile(),list.get(i).getEncryptfile());//加密文件名称
								fileto.renameTo(encryptFile);
								String enpcryptpath=encryptService.decryptFile(seed, encryptFile.getAbsolutePath(),true);
								logger.info("解密后的文件是"+enpcryptpath);
								fileto=new File(enpcryptpath);//解密后的文件
							}
							
							//解压缩处理 复制文件后进行 解压缩处理，一一对应
							String compress=list.get(i).getCompress();//得到对应的压缩信息
							if (compress.equals("1")) {//解压缩fileto文件
								File tarFile=new File(fileto.getParentFile(), list.get(i).getCompressfile());
								fileto.renameTo(tarFile);//还原成.gz文件
								String path=compressService.uncompress(tarFile,true);
								fileto=new File(path);
								logger.info("解压后的文件是"+path);
								fileto.renameTo(new File(recvmetadir, attachements[i]));//还原文件名
							}
							
						}
					}
						fileData.setFilehome(recvmetadir.getAbsolutePath());
						
						//路由更新需要读取原来传来的信息
						//将发送状态修改为发送中，并更新相关的路由日志
						//String syscode = fileData.getRecvSyscode();
						AdapterInfo recvAdapterInfo = baseInfoService.getAdapterInfo(fileData.getRecvNodecode(), fileData.getRecvAdaptorcode());//baseInfoService.getSysServiceInfoBySysCode(syscode);
						if (recvAdapterInfo==null || "".equals(recvAdapterInfo.getWsdlUrl()) ) {
							msg = "发送给接收适配器失败,根据系统编码["+fileData.getRecvNodecode()+"]和适配器编码["+fileData.getSendAdaptorcode()+"]并未找到适配器";
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								RouteLog.setRemoteSys(fileData, AppConst.NO, expiredStatus.getMsg()+"  "+msg, AppConst.dtFormat.format(new Date()));//更新路由状态
								fileData.setSendStatus(AppConst.SendStatus.FAIL.value());//发送失败
								fileData.setModified(new Date());
								failDataList.add(fileData);
							}else{//重新发送
								fileData.setModified(new Date());
								RouteLog.setRemoteSys(fileData, AppConst.NO, "消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(new Date()));//更新路由状态
								if ("2".equals(fileData.getThroughGap())) {
									fileData.setSendStatus( AppConst.SendStatus.ANALYZE_SUCESS.value());
									resendDataList1.add(fileData);
								}else{
									fileData.setSendStatus( AppConst.SendStatus.READY.value());
									resendDataList.add(fileData);
								}
							}
							
							//更新交换
							RecvFileData recvFileData=new RecvFileData();
							BeanMapper.copy(fileData, recvFileData);
							recvFileDataService.insertOrUpdate(recvFileData);//存数据库
							successDataList.add(fileData);
							
							continue;
						}
						
						String address = recvAdapterInfo.getWsdlUrl();
						String resps = null;
						Date now = new Date();
						try {
							/*DataExchRecvService client = (DataExchRecvService) WebserviceUtil.getServicePort(address,
									DataExchRecvService.class);
							*/
							HttpDataExchRecvService client=new HttpDataExchRecvService(address);
							Posthead formmatPosthead=this.formatt(XstreamUtil.toObject(Posthead.class, fileData.getPosthead()), fileData.getRecvNodecode(), fileData.getRecvAdaptorcode());
						    
						    
							resps = client.receiveFileMsg(XstreamUtil.toXml(formmatPosthead),
									fileData.getMetaData(),JsonUtil.toObjectList(fileData.getFileItems(), String.class));
							msg = "目的系统接收成功";
							status.setSuccess(true);
							status.setMsg(msg);
							RouteLog.setRemoteSys(fileData, AppConst.YES, msg, AppConst.dFormat.format(now));//更新路由状态
							fileData.setSendStatus(AppConst.SendStatus.SENT.value());//发送成功
							fileData.setReciverSigned(resps);
							fileData.setModified(new Date());
						} catch (Exception e) {
							msg = "发送给接收适配器失败，失败原因:"+e.getMessage();
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								status.setSuccess(true);
								RouteLog.setRemoteSys(fileData, AppConst.NO, expiredStatus.getMsg()+" "+msg, AppConst.dFormat.format(now));//更新路由状态
								fileData.setSendStatus(AppConst.SendStatus.FAIL.value());//发送成功
								fileData.setModified(new Date());
								failDataList.add(fileData);
							}else{//重新发送
								fileData.setModified(new Date());
								RouteLog.setRemoteSys(fileData, AppConst.NO,  "消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(now));//更新路由状态
								if ("2".equals(fileData.getThroughGap())) {
									fileData.setSendStatus( AppConst.SendStatus.ANALYZE_SUCESS.value());
									resendDataList1.add(fileData);
								}else{
									fileData.setSendStatus( AppConst.SendStatus.READY.value());
									resendDataList.add(fileData);
								}
							}
							//更新交换
							RecvFileData recvFileData=new RecvFileData();
							BeanMapper.copy(fileData, recvFileData);
							recvFileDataService.insertOrUpdate(recvFileData);//存数据库
							successDataList.add(fileData);
							continue;
						}
						RecvFileData recvFileData=new RecvFileData();
						BeanMapper.copy(fileData, recvFileData);
						recvFileDataService.insertOrUpdate(recvFileData);//存数据库
						successDataList.add(fileData);
					}
			}
	    }catch (Exception e) {
			msg = "发送到目的节点出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}finally{
			this.updateLocalSendStatus(successDataList, AppConst.SendStatus.SENT.value()); //发送成功
			this.updateLocalSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateLocalSendStatus(resendDataList1, AppConst.SendStatus.ANALYZE_SUCESS.value());		//等待重发
			this.updateLocalSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		msg = "发送到目的节点成功";
		status.setSuccess(true);
		status.setMsg(msg);
		return status;
	}
	/**
	 * 通过网闸节点刻盘
	 * @return
	 */
	public Status waitCarvedDiscsCrossNet(){
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		NodeInfo localNode=null;
		List<CrossNetTmpFileData> successDataList = new ArrayList<CrossNetTmpFileData>(); //往管道发送成功的数据
		List<CrossNetTmpFileData> resendDataList = new ArrayList<CrossNetTmpFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<CrossNetTmpFileData> failDataList = new ArrayList<CrossNetTmpFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			localNode=baseInfoService.getCurrentNodeInfo();
			//获取待发送的数据
			List<CrossNetTmpFileData> unsendDataList = crossNetTmpFileDataService.getCarvedDiscs();
			//todo 跨网生成跨网文件暂不考虑
			if (CollectionUtil.hasElement(unsendDataList)) {
				for (CrossNetTmpFileData fileData : unsendDataList) {
					msg = "等待刻盘";
					fileData.setSendStatus(AppConst.SendStatus.WAIT_CARVED_DISCS.value());
					fileData.setModified(new Date());
					RouteLog.setWaitCarvedDiscs(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				
				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateCrossNetSendStatus(unsendDataList, AppConst.SendStatus.WAIT_CARVED_DISCS.value());
				if (!status.isSuccess()) {
					msg = "等待刻盘失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}
				
				
				for (CrossNetTmpFileData fileData : unsendDataList) {
					
					try {
						carvedDiscsDataService.generateCarvedDiscsData(fileData);
						successDataList.add(fileData);
					} catch (Exception e) {
						msg = "等待刻盘失败";
						fileData.setSendStatus(AppConst.SendStatus.FAIL.value());
						fileData.setModified(new Date());
						RouteLog.setWaitCarvedDiscs(fileData, AppConst.NO, msg, AppConst.dtFormat.format(now));
						failDataList.add(fileData);
					}
					
					if (fileData.getSendNodecode().equals(localNode.getNodeCode())) {
						SendFileData sendFileData=new SendFileData();
						BeanMapper.copy(fileData, sendFileData);
						sendFileDataService.update(sendFileData);
					}else{
						RecvFileData recvFileData=new RecvFileData();
						BeanMapper.copy(fileData, recvFileData);
						//网闸刻盘
						File file = new File(globalToSendrespDir, recvFileData.getOrderId() +AppConst.RouteOrder.ROUTE_2.getOrder()+ ".xml");
						File parent = file.getParentFile();
						if ((parent.exists() || parent.mkdirs())) {
							XstreamUtil.toXmlfile(recvFileData, file);
						}
					}
				}
				msg = "本节点内数据发送成功";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}else{
				msg = "本节点内数据发送成功：没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "本节点内数据发送出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
		}finally{
			this.updateCrossNetSendStatus(successDataList, AppConst.SendStatus.WAIT_CARVED_DISCS.value()); //等待刻盘
			this.updateCrossNetSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateCrossNetSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		return status;
	}
	
	/**
	 * 从内网到外网需要刻盘
	 * @return
	 */
	public Status waitCarvedDiscs(){
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		List<SendFileData> successDataList = new ArrayList<SendFileData>(); //往管道发送成功的数据
		List<SendFileData> resendDataList = new ArrayList<SendFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> failDataList = new ArrayList<SendFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			//获取待发送的数据
			List<SendFileData> unsendDataList = sendFileDataService.getSendOutNetWorkList();
			//todo 跨网生成跨网文件暂不考虑
			if (CollectionUtil.hasElement(unsendDataList)) {
				
				for (SendFileData fileData : unsendDataList) {
					msg = "等待刻盘";
					fileData.setSendStatus(AppConst.SendStatus.WAIT_CARVED_DISCS.value());
					fileData.setModified(new Date());
					RouteLog.setWaitCarvedDiscs(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateLocalSendStatus(unsendDataList, AppConst.SendStatus.WAIT_CARVED_DISCS.value());
				if (!status.isSuccess()) {
					msg = "等待刻盘失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}
				
				for (SendFileData fileData : unsendDataList) {
					try {
						carvedDiscsDataService.generateCarvedDiscsData(fileData);
						successDataList.add(fileData);
					} catch (Exception e) {
						logger.error("刻盘失败");
						msg = "等待刻盘失败";
						fileData.setSendStatus(AppConst.SendStatus.FAIL.value());
						fileData.setModified(new Date());
						RouteLog.setWaitCarvedDiscs(fileData, AppConst.NO, msg, AppConst.dtFormat.format(now));
						failDataList.add(fileData);
					}
					
				}
				msg = "本节点内数据发送成功";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}else{
				msg = "本节点内数据发送成功：没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "本节点内数据发送出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
		}finally{
			this.updateLocalSendStatus(successDataList, AppConst.SendStatus.WAIT_CARVED_DISCS.value()); //等待刻盘
			this.updateLocalSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateLocalSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		return status;
	}
	
	
	/**
	 * 从内网到外网需要刻盘
	 * @return
	 */
	public Status carvedDiscs(FileData fileData){
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		NodeInfo localNode=null;
		try {
			localNode=baseInfoService.getCurrentNodeInfo();
			if (fileData instanceof SendFileData) {
				SendFileData sendFileData=(SendFileData) fileData;
				msg = "已刻盘";
				sendFileData.setSendStatus(AppConst.SendStatus.CARVED_DISCS.value());
				sendFileData.setModified(new Date());
				RouteLog.setCarvedDiscs(sendFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				RecvFileData recvFileData=new RecvFileData();
				BeanMapper.copy(sendFileData, recvFileData);
				sendFileDataService.update(sendFileData);
				recvFileDataService.update(recvFileData);
			}else if(fileData instanceof RecvFileData){
				RecvFileData recvFileData=(RecvFileData) fileData;
				msg = "已刻盘";
				recvFileData.setSendStatus(AppConst.SendStatus.CARVED_DISCS.value());
				recvFileData.setModified(new Date());
				RouteLog.setCarvedDiscs(recvFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				SendFileData sendFileData=new SendFileData();
				BeanMapper.copy(recvFileData, sendFileData);
				recvFileDataService.update(recvFileData);
				sendFileDataService.update(sendFileData);
			}else if(fileData instanceof CrossNetTmpFileData){
				CrossNetTmpFileData tmpFileData=(CrossNetTmpFileData) fileData;
				msg = "已刻盘";
				tmpFileData.setSendStatus(AppConst.SendStatus.CARVED_DISCS.value());
				tmpFileData.setModified(new Date());
				RouteLog.setCarvedDiscs(tmpFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				SendFileData sendFileData=new SendFileData();
				BeanMapper.copy(tmpFileData, sendFileData);
				crossNetTmpFileDataService.update(tmpFileData);
				if (localNode.getNodeCode().equals(sendFileData.getSendNodecode())) {
					sendFileDataService.update(sendFileData);
				}else{
					RecvFileData recvFileData=new RecvFileData();
					BeanMapper.copy(tmpFileData, recvFileData);
					//路由2
					File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
					File parent = file.getParentFile();
					if ((parent.exists() || parent.mkdirs())) {
						XstreamUtil.toXmlfile(recvFileData, file);
					}
				}
			}
				msg = "刻盘成功";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
		} catch (Exception e) {
			msg = "刻盘出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
		}
		return status;
	}
	
	/**
	 * 发送到外网网闸节点，或者中央节点
	 */
	public Status sendDataToOuterSendPipeline() {
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		List<SendFileData> successDataList = new ArrayList<SendFileData>(); //往管道发送成功的数据
		List<SendFileData> resendDataList = new ArrayList<SendFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> failDataList = new ArrayList<SendFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			//获取待发送的数据
			List<SendFileData> unsendDataList = sendFileDataService.getSendInnerNetWorkList();
			//todo 跨网生成跨网文件暂不考虑
			if (CollectionUtil.hasElement(unsendDataList)) {
				for (SendFileData fileData : unsendDataList) {
					msg = "发送到网闸节点成功";
					fileData.setSendStatus(AppConst.SendStatus.LOCAL_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setSendDataToOuterSendPipeline(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateLocalSendStatus(unsendDataList, AppConst.SendStatus.LOCAL_SENDING.value());
				if (!status.isSuccess()) {
					msg = "发送到目的节点失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}

				for (SendFileData fileData : unsendDataList) {
					try {
						String nodecode = fileData.getOutGapNodeCode();
						PipeLineFtp ftp = distributedNodeInfoService.getFtpPipeLineByNodeCode(nodecode);
						String host = ftp.getIp();//发送目的服务器的地址
						String tousername = AppConst.EMBFTP.EMBFTP_ADMIN_USERID;//发送目的服务器的ftp用户名
						String topassword = AppConst.EMBFTP.EMBFTP_ADMIN_PWD+" "+tousername+" "+AppConst.getAdminAuthCode();//发送目的服务器的ftp密码
						String fromlocal = fileData.getFilehome();
						String storepaths = fileData.getStorepaths();
						int port = ftp.getPort();
						String[] filenames = storepaths.split(";");
						logger.info("sendDataToOuterSendPipeline需要上传的数据文件个数"+filenames.length);
						for (String filename : filenames) {
							String tolocalmeta = File.separator + crossmetadataDir;//ftp传输路径
							File fromfile = new File(fromlocal, filename);
							tolocalmeta = tolocalmeta + File.separator + filename;
							status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, fromfile, tolocalmeta);
							logger.info(tolocalmeta + "文件上传结果::"+status);
							//发送失败。该条记录不在发送
							if (!status.isSuccess()) {
								break;
							}
						}
						if (status.isSuccess()) {
							//成功后发送fileData
							String tolocalxml = File.separator + crossxmlDir + File.separator + fileData.getOrderId() + ".xml";
							RouteLog.setSendDataToOuterSendPipeline(fileData, AppConst.YES, "发送到网闸节点成功", AppConst.dFormat.format(now));//更新路由状态，如果失败了。后面会滚这部分信息
							status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, XstreamUtil.toXml(fileData),
									tolocalxml);
							logger.info(tolocalxml + "文件上传结果::"+status);
							if (status.isSuccess()) {
								fileData.setModified(new Date());
								successDataList.add(fileData);
							} else {
								//TODO:判断过期的消息
								fileData.setModified(new Date());
								RouteLog.setSendDataToOuterSendPipeline(fileData, AppConst.NO, status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
								failDataList.add(fileData);
							}
						} else {
							fileData.setModified(new Date());
							RouteLog.setSendDataToOuterSendPipeline(fileData, AppConst.NO, status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
							failDataList.add(fileData);
						}

					} catch (Exception e) {
						msg = "发送到网闸节点失败：" + e.getMessage();
						fileData.setModified(new Date());
						RouteLog.setSendDataToOuterSendPipeline(fileData, AppConst.NO, msg, AppConst.dtFormat.format(now));//更新路由状态
						failDataList.add(fileData);
					}
				}

			} else {
				msg = "没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "发送到网闸节点出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}finally{
			this.updateLocalSendStatus(successDataList, AppConst.SendStatus.LOCAL_SENT.value()); //发送成功
			this.updateLocalSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateLocalSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		msg = "发送到网闸节点成功";
		status.setSuccess(true);
		status.setMsg(msg);
		return status;
	}
	

	public Status outerEntrepotStore() {
		String msg = "";
		Status status = Status.getInstance();
		try {
			logger.info("outerEntrepotStorek开始执行");
			FtpUser user = ftpUserService.getFtpadmin();
			String home = user.getHomedirectory();
			File dir = new File(home, crossxmlDir);
			if (!dir.isDirectory()) {
				status.setMsg(dir.getAbsolutePath() + "不是一个文件夹。");
				status.setSuccess(false);
				return status;
			}
			File[] filexmls = dir.listFiles();
			logger.info("outerEntrepotStorek执行解析的文件个数:"+filexmls.length);
			if (filexmls == null || filexmls.length <= 0) {
				logger.info(dir.getAbsolutePath() + "下没有文件需要解析");
				status.setSuccess(true);
				status.setMsg(dir.getAbsolutePath() + "下没有文件需要解析");
				return status;
			}
			
			for (File filexml : filexmls) {
				try {
					if (!checkFilename(filexml)) {
						continue;//非xml文件不解析
					}
					SendFileData sendFileData = XstreamUtil.toObject(SendFileData.class,filexml);
					CrossNetTmpFileData tmpFileData = new CrossNetTmpFileData();
					BeanMapper.copy(sendFileData, tmpFileData);
					
					//将数据文件移到globalUploadmetadataDir
					String[] storefiles=tmpFileData.getStorepaths().split(";");
					File homeDir=new File(user.getHomedirectory(),crossmetadataDir);
					File globaluploalpath=new File(globalUploadmetadataDir,AppConst.dFormat.format(new Date()));
					if (!globaluploalpath.exists()) {
						globaluploalpath.mkdirs();
					}
					File srcFile=null;
					try {
						for (String string : storefiles) {
							srcFile=new File(homeDir,string);
							File destFile=new File(globaluploalpath,string);
							FileUtils.copyFile(srcFile, destFile);
							//srcFile.delete();
						}
					} catch (Exception e) {
						logger.error("文件拷贝异常:id【"+sendFileData.getOrderId()+"】对应的数据文件【"+srcFile.getAbsolutePath()+"】拷贝异常"+e);
						continue;
					}
					tmpFileData.setFilehome(globaluploalpath.getAbsolutePath());
					//初始化接收记录
					tmpFileData.setModified(new Date());
					tmpFileData.setSendStatus(AppConst.SendStatus.OUTER_ENTREPOT_READY.value());
					RouteLog.setOuterEntrepotStore(tmpFileData, AppConst.YES, "外网网闸存储", AppConst.dtFormat.format(new Date()));
					crossNetTmpFileDataService.insertOrUpdate(tmpFileData);
					
					RecvFileData recvFileData=new RecvFileData();
					BeanMapper.copy(tmpFileData, recvFileData);
					//路由1
					File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_1.getOrder() + ".xml");
					File parent = file.getParentFile();
					if (filexml.delete() && (parent.exists() || parent.mkdirs())) {
						XstreamUtil.toXmlfile(recvFileData, file);
					}
				} catch (Exception e) {
					logger.error("[outerEntrepotStore]执行转换发生异常:" + e.getMessage());
				}
			}
		} catch (ServiceException e) {
			msg = "远程落地--检查FTP文件失败，" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		} catch (Exception e) {
			msg = "远程落地--检查FTP文件失败，" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}
		return null;
	}
	
	
	
	/**
	 * 拆包上传到网闸
	 * @throws FileSplitException 
	 */
	private Packet  splitFile(File file) throws FileSplitException{
		 int index=file.getAbsolutePath().lastIndexOf(".");
		    String parent=file.getAbsolutePath().substring(0,index);
			Packet packet=fileSplit.splitFile(file, parent, AppConst.FTP_FILESIZE, false);
			return packet;
	}
	
	
	private boolean isContains(String str,List<String> list){
		for (String string : list) {
			if (str.equals(string)) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 
	 * @param file
	 * @return 返回false表示不是一个拆包文件，返回true表示是一个拆包文件
	 * @throws FileSplitException 
	 */
	private Status unionFile(File file) throws FileSplitException{
		Status status=Status.getInstance();
			List<String> list=fileSplit.getSplitFileListFromSplitFile(file.getAbsolutePath());
			//判断当前文件是否有所有的拆包文件，如果有则进行合并
			File[] files=file.getParentFile().listFiles();
			boolean flag=false;//用来标识当前目录是否有所有的拆包文件
			int count=0;//包含的个数
			for (int i = 0; i < files.length; i++) {
				flag=isContains(files[i].getAbsolutePath(), list);
				if (flag) {
					count++;
					continue;
				}
				if (count==list.size()) {
					break;
				}
			}
			
			if (count!=list.size()) {
				status.setMsg("是拆包后的一个子包，但是当前的子包还不能合并成一个包");
				status.setSuccess(flag);
				return status;
			}
			
			//合并包
			String path;
			try {
				path = fileSplit.unionFile(true, list);
				status.setSuccess(true);
				status.setMsg("组包成功");
				status.setData(path);
				return status;
			} catch (FileSplitException e) {
				status.setSuccess(false);
				status.setMsg("组包失败:"+e.getMessage());
				return status;
			}
			
		
	}
	/**
	 * 
	 */
	private Status uploadToGap(File file){
		return FtpUtil.upload(new FTPClient(),inIp,
				inUserName,
				inPassword,
				inPort, file,
				inOutput+File.separator + file.getName());
	}
	/**
	 * 定时任务，将文件发送至外网网闸的FTP目录
	 * @return
	 */
	public Status outerGAP() {
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		List<CrossNetTmpFileData> successDataList = new ArrayList<CrossNetTmpFileData>(); //往ftp server发送成功的数据
		List<CrossNetTmpFileData> resendDataList = new ArrayList<CrossNetTmpFileData>(); //待重发的数据，ftp server发送失败时将进行重发
		List<CrossNetTmpFileData> failDataList = new ArrayList<CrossNetTmpFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		BufferedWriter fw = null;
		List<String> delList=new ArrayList<String>();//需要删除的文件目录
		//获取待发送的网闸的数据
//		NodeInfo localNode=null;
		try {
//			localNode=baseInfoService.getCurrentNodeInfo();
			List<CrossNetTmpFileData> unsendDataList = crossNetTmpFileDataService.getLocaleGapUnsentList();
			//如果unsendDataList 不为空
			if (CollectionUtil.hasElement(unsendDataList)) {

				//更新状态 为 发送到网闸
				for (CrossNetTmpFileData fileData : unsendDataList) {
					msg = "数据发送至外网网闸的FTP目录成功";
					fileData.setSendStatus(AppConst.SendStatus.OUTER_ENTREPOT_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setOuterGAP(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//与发送文件到外网网闸的日志信息
				}

				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateCrossSendStatus(unsendDataList, AppConst.SendStatus.OUTER_ENTREPOT_SENDING.value());

				//将数据上传到FTP服务器
				for (CrossNetTmpFileData fileData : unsendDataList) {
					try {
						//将文件打包
						status=zipFile(fileData);
						if (status.isSuccess()) {
							File zip=new File(status.getData().toString());
							delList.add(zip.getAbsolutePath());//打包文件需要删除
							//进行拆包处理
							Packet packet=null;
							try {
								packet=this.splitFile(zip);
								if (packet!=null) {
									List<String> listFile=packet.getPacketfile();
									delList.addAll(listFile);//删除拆包文件
									for (String string : listFile) {
										status =uploadToGap(new File(string));
										if (!status.isSuccess()) {
											logger.error("子包"+string+"上传到网闸失败");
											break;
										}
									}
									delList.add(new File(listFile.get(0)).getParent());//删除拆包文件的上级目录
								}else{
									//将文件发送到ftp 服务器
									status =uploadToGap(zip);
								}
							} catch (Exception e) {
								status.setSuccess(false);
								status.setMsg(e.getMessage());
							}
						}
						
						if (status.isSuccess()) {
							fileData.setModified(new Date());
							fileData.setSendStatus(AppConst.SendStatus.OUTER_ENTREPOT_SUCCESS.value());
							RouteLog.setOuterGAP(fileData, AppConst.YES, status.getMsg(),
									AppConst.dtFormat.format(now));//更新路由状态
							successDataList.add(fileData);
						} else {
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
							msg=status.getMsg();
							if (status.isSuccess()) {
								fileData.setModified(new Date());
								fileData.setSendStatus(AppConst.SendStatus.FAIL.value());
								fileData.setThroughGap("2");//转为刻盘
								RouteLog.setOuterGAP(fileData, AppConst.NO,"已转为刻盘,由于发送到网闸失败:"+ expiredStatus.getMsg()+" "+msg,
										AppConst.dtFormat.format(now));//更新路由状态
								failDataList.add(fileData);
							} else {
								fileData.setModified(new Date());
								fileData.setSendStatus(AppConst.SendStatus.OUTER_ENTREPOT_READY.value());
								RouteLog.setOuterGAP(fileData, AppConst.NO, "消息已重发，重发原因<<"+msg+">>",
										AppConst.dtFormat.format(now));//更新路由状态
								resendDataList.add(fileData);
							}
						}
						RecvFileData recvFileData=new RecvFileData();
						BeanMapper.copy(fileData, recvFileData);
						//路由2
						File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
						File parent = file.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							XstreamUtil.toXmlfile(recvFileData, file);
						}
					} catch (Exception e) {
						failDataList.add(fileData);
					}
				}
				msg = "通知数据发送系统成功";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			} else {
				msg = "数据投递结果反馈给网闸节点成功：没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "本节点内数据发送出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
		} finally {
			this.updateCrossSendStatus(successDataList, AppConst.SendStatus.OUTER_ENTREPOT_SUCCESS.value()); //发送成功
			this.updateCrossSendStatus(resendDataList, AppConst.SendStatus.OUTER_ENTREPOT_READY.value()); //等待重发
			this.updateCrossSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
			if (fw != null) {
				try {
					fw.close();
				} catch (IOException e) {
					logger.error(e);
				}
			}
			
			//删除打包文件和拆包文件
			if (delList!=null && !delList.isEmpty()) {
				for (String path : delList) {
					boolean flag=TurboUtil.deleteFile(new File(path));
					logger.info("上传网闸后删除文件["+path+"],删除结果"+flag);
				}
			}
		}
		return status;
	}
	
	
	@Override
	public Status innerEntrepotStore() {
		String msg = "";
		Status status = Status.getInstance();
		FTPClient ftpClient = new FTPClient();
		ftpClient.setConnectTimeout(AppConst.FTP_TIMEOUT);
		ftpClient.setDefaultTimeout(20000);
		ftpClient.setDataTimeout(20000);      //设置数据超时   10秒
		ftpClient.setControlEncoding("utf-8");
		FileOutputStream fos = null;
		NodeInfo localNode=null;
		// 登录FTP服务器  
				try {
					localNode=baseInfoService.getCurrentNodeInfo();
					if(!NetUtil.canConnect(inIp, inPort))return null;
					ftpClient.connect(inIp, inPort);
					ftpClient.login(inUserName, inPassword);
					ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);//设置文件的传输方式。
					String fileName = "";
					// FTP服务器要被下载的文件(路径加文件名)
					String remoteFileName = "";
					// 下载后在本地生成的文件(路径加文件名) 
					File localFile = null;
					// 把符合条件的文件下载到本地 
					if (inOutput!=null && !"".equals(inOutput)) {
						ftpClient.changeWorkingDirectory(inOutput);
					}
					
					File temp=new File(localFtpPut);//创建临时目录
					if (!temp.exists()) {
						temp.mkdirs();
					}
					FTPFile[] files = ftpClient.listFiles();
					for (FTPFile file : files) {
						//如果文件是以.zip结尾或者.split结尾的
						if (file.isFile() && (file.getName().endsWith(".zip") || file.getName().endsWith(FileSplitStatic.SPLIT_FILE_SUFFIX)) ) {
							fileName = file.getName();
							if (!fileName.substring(0, 6).equals(localNode.getNodeCode().substring(0, 6))) {
								continue;
							}
							remoteFileName = fileName;
							localFile = new File(localFtpPut ,fileName);
							fos = new FileOutputStream(localFile);
							ftpClient.setBufferSize(1024 * 1024 * 10);
							ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
							ftpClient.enterLocalPassiveMode();
							ftpClient.retrieveFile(fileName, fos);
							ftpClient.enterLocalPassiveMode();
							fos.flush();
							ftpClient.deleteFile(remoteFileName);//删除下载后的文件
							try {
								status=this.unionFile(localFile);
								if (status.isSuccess()) {//如果为true合并包成功
									if (status.getData()!=null && !"".equals(status.getData().toString())) {
										status=analyzeZip(new File(status.getData().toString()));//解析合并后的文件
									}else{
										continue;
									}
									
								}else{//文件时拆包后的一个子包
									logger.warn(status.getMsg());;
									continue;
								}
							} catch (Exception e) {//非拆包文件，直接解析
								status=analyzeZip(localFile);
							}
							
							
							if (!status.isSuccess()) {
								continue;
							}
							localFile.delete();
							
						}
					}
				} catch (Exception e) {
					logger.error(msg, e);
					msg = "下载出现异常:" + e.fillInStackTrace();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				} finally {
					// 关闭连接  
					IOUtils.closeQuietly(fos);
					try {
						if (fos!=null) {
							fos.close();
						}
						ftpClient.disconnect();
					} catch (IOException e) {
						logger.error(msg, e);
						msg = "下载出现异常:" + e.fillInStackTrace();
						status.setSuccess(false);
						status.setMsg(msg);
						return status;
					}
				}
		return status;
	}
	
	
	public Status sendDataToInnerSendPipline() {
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		List<CrossNetTmpFileData> successDataList = new ArrayList<CrossNetTmpFileData>(); //往管道发送成功的数据
		List<CrossNetTmpFileData> resendDataList = new ArrayList<CrossNetTmpFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<CrossNetTmpFileData> failDataList = new ArrayList<CrossNetTmpFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败

		try {
			//获取待发送的数据
			List<CrossNetTmpFileData> unsendDataList = crossNetTmpFileDataService.getInnerEntrepotUnsentList();
			//todo 跨网生成跨网文件暂不考虑
			if (CollectionUtil.hasElement(unsendDataList)) {
				for (CrossNetTmpFileData fileData : unsendDataList) {
					msg = "数据发送至传输管道成功";
					fileData.setSendStatus(AppConst.SendStatus.INNER_ENTREPOT_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setInnerSendPipeline(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}

				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateCrossNetSendStatus(unsendDataList, AppConst.SendStatus.INNER_ENTREPOT_SENDING.value());

				if (!status.isSuccess()) {
					msg = "发送到目的节点失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}

				for (CrossNetTmpFileData fileData : unsendDataList) {
					try {
						
						//如果是本节点接收
						if (fileData.getRecvNodecode().equals(fileData.getInnerGapNodeCode())) {
							//初始化接收记录
							fileData.setModified(new Date());

							String to = fileData.getRecvAdaptorcode();
							FtpUser touser = ftpUserService.get(to);

							String[] attachements = fileData.getFilepaths().split(";");
							String[] storepaths = fileData.getStorepaths().split(";");

							/********先压缩，后加密   最后处理先解密 再解压缩**************/
							//获取解压缩处理的service
							CompressService compressService = CompressServiceFactory.createCompressService(COMPRESS_ALGORITHM.JAVA_GZIP);
							//解密处理
							EncryptService encryptService = EncryptServiceFactory.createEncryptService(ENCRYPT_ALGORITHM.DES);
							//从头文件获取解压缩信息
							List<ProcessInfo> list=XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getProcesses().getProcess();
							
							File recvmetadir = new File(new File(touser.getHomedirectory(), recvmetadataDir),
									fileData.getSendNodecode());
//							recvmetadir = new File(recvmetadir,to);
							for (int i = 0; i < attachements.length; i++) {
								File file = new File(fileData.getFilehome(), storepaths[i]);
								File fileto = new File(recvmetadir, attachements[i]);
								File parent = fileto.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									FileUtils.copyFile(file, fileto);//复制文件
									
									//对fileto进行解密和解压缩
		                             //解密处理
									String encrypt=list.get(0).getEncrypt();
									if (encrypt.equals("1")) {//解密
										String seed=encryptService.getSeed(XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getFrom().getNodecode()+XstreamUtil.toObject(Posthead.class, fileData.getPosthead()).getFrom().getAdaptorcode());
										File encryptFile=new File(fileto.getParentFile(),list.get(i).getEncryptfile());//加密文件名称
										fileto.renameTo(encryptFile);
										String enpcryptpath=encryptService.decryptFile(seed, encryptFile.getAbsolutePath(),true);
										logger.info("解密后的文件是"+enpcryptpath);
										fileto=new File(enpcryptpath);//解密后的文件
									}
									
									//解压缩处理 复制文件后进行 解压缩处理，一一对应
									String compress=list.get(i).getCompress();//得到对应的压缩信息
									if (compress.equals("1")) {//解压缩fileto文件
										File tarFile=new File(fileto.getParentFile(), list.get(i).getCompressfile());
										fileto.renameTo(tarFile);//还原成.gz文件
										String path=compressService.uncompress(tarFile,true);
										fileto=new File(path);
										logger.info("解压后的文件是"+path);
										fileto.renameTo(new File(recvmetadir, attachements[i]));//还原文件名
									}
								}
							}
							//路由更新需要读取原来传来的信息
							msg = "远程落地成功";
							status.setSuccess(true);
							status.setMsg(msg);
							RouteLog.setRemoteStore(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
							RecvFileData recvFileData=new RecvFileData();
							BeanMapper.copy(fileData, recvFileData);
							recvFileData.setFilehome(recvmetadir.getAbsolutePath());
							recvFileDataService.insertOrUpdate(recvFileData);//存数据库
							crossNetTmpFileDataService.insertOrUpdate(fileData);
							continue;
						}
						
						
						String nodecode = fileData.getRecvNodecode();
						PipeLineFtp ftp = distributedNodeInfoService.getFtpPipeLineByNodeCode(nodecode);
						String host = ftp.getIp();//发送目的服务器的地址
						String tousername = AppConst.EMBFTP.EMBFTP_ADMIN_USERID;//发送目的服务器的ftp用户名
						String topassword = AppConst.EMBFTP.EMBFTP_ADMIN_PWD+" "+tousername+" "+AppConst.getAdminAuthCode();//发送目的服务器的ftp密码
						String fromlocal = fileData.getFilehome();
						String storepaths = fileData.getStorepaths();
						int port = ftp.getPort();
						String[] filenames = storepaths.split(";");
						for (String filename : filenames) {
							String tolocalmeta = File.separator + recvmetadataDir;//ftp传输路径
							File fromfile = new File(fromlocal, filename);
							tolocalmeta = tolocalmeta + File.separator + filename;
							status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, fromfile, tolocalmeta);
							//发送失败。该条记录不在发送
							if (!status.isSuccess()) {
								break;
							}
						}
						if (status.isSuccess()) {
							//成功后发送fileData
							String tolocalxml = File.separator + recvxmlDir + File.separator + fileData.getOrderId() + ".xml";
							RouteLog.setInnerSendPipeline(fileData, AppConst.YES, "发送到目的节点成功", AppConst.dtFormat.format(now));//更新路由状态，如果失败了。后面会滚这部分信息
							SendFileData sendFileData=new SendFileData();
							BeanMapper.copy(fileData, sendFileData);
							status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, XstreamUtil.toXml(sendFileData),
									tolocalxml);
							if (status.isSuccess()) {
								fileData.setModified(new Date());
								successDataList.add(fileData);
							} else {
								//TODO:判断过期的消息
								fileData.setModified(new Date());
								RouteLog.setInnerSendPipeline(fileData, AppConst.NO, status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
								failDataList.add(fileData);
							}
						} else {
							fileData.setModified(new Date());
							RouteLog.setInnerSendPipeline(fileData, AppConst.NO, status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
							failDataList.add(fileData);
						}

					} catch (Exception e) {
						msg = "发送到目的节点失败：" + e.getMessage();
						fileData.setModified(new Date());
						RouteLog.setInnerSendPipeline(fileData, AppConst.NO, msg, AppConst.dtFormat.format(now));//更新路由状态
						failDataList.add(fileData);
					}
				}

			} else {
				msg = "没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "发送到目的节点出现异常:" + e.fillInStackTrace();
			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}finally{
			this.updateCrossNetSendStatus(successDataList, AppConst.SendStatus.INNER_ENTREPOT_SEND.value()); //发送成功
			this.updateCrossNetSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateCrossNetSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		msg = "发送到目的节点成功";
		status.setSuccess(true);
		status.setMsg(msg);
		return status;
	}

	/**
	 * 第2步
	 * 此方法逻辑
	 * 1、查找发送状态为待发送的数据列表
	 * 2、锁定这批数据:将这批待发送的数据的状态更新为“发送中”
	 * 3、遍历这个列表里面的数据，根据数据的管道类型发送至不同的管道中
	 * 4、处理发送结果
	 * 4.1:发送成功，更新路由状态
	 * 4.2：发送失败，更新路由状态
	 * 4.2.1：消息没失效？等待重发
	 * 4.2.2：消息失效？将状态值为发送失败
	 */
	@Override
	public Status sendDataToPipline() {
		 logger.info("进入方法sendDataToPipline.....");
		String msg = "";
		Status status = Status.getInstance();
		Date now = new Date();
		List<SendFileData> successDataList = new ArrayList<SendFileData>(); //往管道发送成功的数据
		List<SendFileData> resendDataList = new ArrayList<SendFileData>();  //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> resendDataList1 = new ArrayList<SendFileData>();  //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> failDataList = new ArrayList<SendFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		
		try {
			//获取待发送的数据
			List<SendFileData> unsendDataList = sendFileDataService.getUnsentList(BATCH_NUM);
			logger.info("进入方法sendDataToPipline,getUnsentList.....按照最小批量5个查询");
			logger.info("进入方法sendDataToPipline,getUnsentList....." + unsendDataList.size());
			//todo 跨网生成跨网文件暂不考虑
			if (CollectionUtil.hasElement(unsendDataList)) {
				for (SendFileData fileData : unsendDataList) {
					msg = "发送到目的节点成功";
					fileData.setSendStatus(AppConst.SendStatus.LOCAL_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setLocalPipeline(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				//将发送状态修改为发送中，并更新相关的路由日志
				status = this.updateLocalSendStatus(unsendDataList, AppConst.SendStatus.LOCAL_SENDING.value());
				logger.info("进入方法sendDataToPipline,updateLocalSendStatus....." + unsendDataList.size());
				if (!status.isSuccess()) {
					msg = "发送到目的节点失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}

				for (SendFileData fileData : unsendDataList) {
					try {
						 logger.info("进入方法sendDataToPipline,共处理【" + unsendDataList.size() + "个】,当前处理【" + (unsendDataList.indexOf(fileData) + 1) + "个】开始KAISHI.....");
						 logger.info("why.................................");
						String nodecode = fileData.getRecvNodecode();
						PipeLineFtp ftp = distributedNodeInfoService.getFtpPipeLineByNodeCode(nodecode);
						logger.info("进入方法sendDataToPipline,getFtpPipeLineByNodeCode....." + ftp);
						String host = ftp.getIp();//发送目的服务器的地址
						String tousername = AppConst.EMBFTP.EMBFTP_ADMIN_USERID;//发送目的服务器的ftp用户名
						String topassword = AppConst.EMBFTP.EMBFTP_ADMIN_PWD+" "+tousername+" "+AppConst.getAdminAuthCode();;//发送目的服务器的ftp密码
						String fromlocal = fileData.getFilehome();
						String storepaths = fileData.getStorepaths();
						int port = ftp.getPort();
						String[] filenames = storepaths.split(";");
						for (String filename : filenames) {
							String tolocalmeta = File.separator + recvmetadataDir;//ftp传输路径
							File fromfile = new File(fromlocal, filename);
							tolocalmeta = tolocalmeta + File.separator + filename;
							 logger.info("进入方法sendDataToPipline,上传数据文件【" + tolocalmeta + "】开始.....");
							status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, fromfile, tolocalmeta);
							logger.info("进入方法sendDataToPipline,上传数据文件【" + tolocalmeta + "】结束....." + status.isSuccess());

							//发送失败。该条记录不在发送
							if (!status.isSuccess()) {
								break;
							}
						}
						if (status.isSuccess()) {
							//成功后发送fileData
							String tolocalxml = File.separator + recvxmlDir + File.separator + fileData.getOrderId() + ".xml";
							RouteLog.setLocalPipeline(fileData, AppConst.YES, "发送到目的节点成功", AppConst.dtFormat.format(now));//更新路由状态，如果失败了。后面会滚这部分信息
							SendFileData sendFileData=new SendFileData();
							BeanMapper.copy(fileData, sendFileData);
							 logger.info("进入方法sendDataToPipline,上传头文件【" + tolocalxml + "】开始.....");
							 status = FtpUtil.upload(TurboFtpClientFactory.createFtpClient(),host, tousername, topassword, port, XstreamUtil.toXml(sendFileData),
										tolocalxml);
				              logger.info("进入方法sendDataToPipline,上传头文件【" + tolocalxml + "】结束....." + status.isSuccess());
							if (status.isSuccess()) {
								fileData.setModified(new Date());
								successDataList.add(fileData);
							} else {
								//失败后判定是否过期
								Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
								if (expiredStatus.isSuccess()) {
									fileData.setModified(new Date());
									RouteLog.setLocalPipeline(fileData, AppConst.NO,expiredStatus.getMsg()+"  失败原因:"+ status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
									failDataList.add(fileData);
								}else{
									fileData.setModified(new Date());
									RouteLog.setLocalPipeline(fileData, AppConst.NO,"消息已重发，重发原因<<"+status.getMsg()+">>", AppConst.dtFormat.format(now));//更新路由状态
									if ("2".equals(fileData.getThroughGap())) {
										fileData.setSendStatus( AppConst.SendStatus.ANALYZE_SUCESS.value());
										resendDataList1.add(fileData);
									}else{
										fileData.setSendStatus( AppConst.SendStatus.READY.value());
										resendDataList.add(fileData);
									}
								}
							}
						} else {
							//失败后判定是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
							if (expiredStatus.isSuccess()) {
								fileData.setModified(new Date());
								RouteLog.setLocalPipeline(fileData, AppConst.NO,expiredStatus.getMsg()+"  失败原因:"+ status.getMsg(), AppConst.dtFormat.format(now));//更新路由状态
								failDataList.add(fileData);
							}else{
								fileData.setModified(new Date());
								RouteLog.setLocalPipeline(fileData, AppConst.NO,"消息已重发，重发原因<<"+status.getMsg()+">>", AppConst.dtFormat.format(now));//更新路由状态
								if ("2".equals(fileData.getThroughGap())) {
									fileData.setSendStatus( AppConst.SendStatus.ANALYZE_SUCESS.value());
									resendDataList1.add(fileData);
								}else{
									fileData.setSendStatus( AppConst.SendStatus.READY.value());
									resendDataList.add(fileData);
								}
							}
						}

					} catch (Exception e) {
						logger.info("方法sendDataToPipline,异常::::"+e);
						msg = "发送到目的节点失败：" + e.getMessage();
						//失败后判定是否过期
						Status expiredStatus = timeoutExpiredStrategy.isExpired(fileData.getCreated());
						if (expiredStatus.isSuccess()) {
							fileData.setModified(new Date());
							RouteLog.setLocalPipeline(fileData, AppConst.NO,expiredStatus.getMsg()+"  失败原因:"+ msg, AppConst.dtFormat.format(now));//更新路由状态
							failDataList.add(fileData);
						}else{
							fileData.setModified(new Date());
							RouteLog.setLocalPipeline(fileData, AppConst.NO,"消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(now));//更新路由状态
							if ("2".equals(fileData.getThroughGap())) {
								fileData.setSendStatus( AppConst.SendStatus.ANALYZE_SUCESS.value());
								resendDataList1.add(fileData);
							}else{
								fileData.setSendStatus( AppConst.SendStatus.READY.value());
								resendDataList.add(fileData);
							}
						}
					}
					 logger.info("进入方法sendDataToPipline,共处理【" + unsendDataList.size() + "个】,当前处理【" + (unsendDataList.indexOf(fileData) + 1) + "个】结束JIESHU.....");
				}
			} else {
				msg = "没有需要发送的数据";
				status.setSuccess(true);
				status.setMsg(msg);
				return status;
			}
		} catch (Exception e) {
			msg = "发送到目的节点出现异常:" + e.fillInStackTrace();
			 logger.info("方法sendDataToPipline,异常::::"+e);

			logger.error(msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}finally{
			this.updateLocalSendStatus(successDataList, AppConst.SendStatus.LOCAL_SENT.value()); //发送成功
			//this.updateLocalSendStatus(resendDataList, AppConst.SendStatus.READY.value()); //等待重发
			this.updateLocalSendStatus(resendDataList, AppConst.SendStatus.READY.value());		//等待重发
			this.updateLocalSendStatus(resendDataList1, AppConst.SendStatus.ANALYZE_SUCESS.value());		//等待重发
			this.updateLocalSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
			 logger.info("方法sendDataToPipline,最后更新状态successDataList【" + successDataList.size() + "条】,failDataList【" + failDataList.size() + "条】.........");
		}
		logger.info("方法sendDataToPipline结束.........");
		msg = "发送到目的节点成功";
		status.setSuccess(true);
		status.setMsg(msg);
		return status;
	}

	
	/*
	第3步。远程入库
	 */

	public Status cleanUpFtpHome() {
		Status status = Status.getInstance();
		FtpUser user;
		try {
			user = ftpUserService.getFtpadmin();
			String home = user.getHomedirectory();
			File dir = new File(home, recvmetadataDir);
			final Date now=new Date();
			if (dir.isDirectory()) {
				//取出超过七天文件，删除
				File[] fs=dir.listFiles(new FileFilter() {
					@Override
					public boolean accept(File pathname) {
						Date preday=DateUtil.operation(now, Calendar.DAY_OF_MONTH, -fileDeleteTime);//前7天的日期
						if (pathname.lastModified()<=preday.getTime()) {
							return true;
						}
						return false;
					}
				});
				for (File file : fs) {
					boolean flag=TurboUtil.deleteFile(file);
					logger.info("删除文件["+file.getName()+"]:"+flag);
				}
			}
			
			//清理crossmetadatDir
			dir = new File(home, crossmetadataDir);
			if (dir.isDirectory()) {
				//取出超过七天文件，删除
				File[] fs=dir.listFiles(new FileFilter() {
					@Override
					public boolean accept(File pathname) {
						Date preday=DateUtil.operation(now, Calendar.DAY_OF_MONTH, -fileDeleteTime);//前7天的日期
						if (pathname.lastModified()<=preday.getTime()) {
							return true;
						}
						return false;
					}
				});
				for (File file : fs) {
					boolean flag=TurboUtil.deleteFile(file);
					logger.info("删除文件["+file.getName()+"]:"+flag);
				}
			}
			
			
			//清理globaluploadmetadata
			dir=new File(globalUploadmetadataDir);
			if (dir.isDirectory()) {
				//取出超过七天文件，删除
				File[] fs=dir.listFiles(new FileFilter() {
					@Override
					public boolean accept(File pathname) {
						Date preday=DateUtil.operation(now, Calendar.DAY_OF_MONTH, -fileDeleteTime);//前7天的日期
						if (pathname.lastModified()<=preday.getTime()) {
							return true;
						}
						return false;
					}
				});
				for (File file : fs) {
					boolean flag=TurboUtil.deleteFile(file);
					logger.info("删除文件["+file.getName()+"]:"+flag);
				}
			}
		} catch (ServiceException e) {
			logger.error("定时清理ftphome目录时失败:"+e);
		}
		return status;
	}
	/*
	第3步。远程入库
	 */

	@Override
	public Status remoteStore() {
		logger.info("进入方法remoteStore。");
		String msg = "";
		Status status = Status.getInstance();
		try {
			FtpUser user = ftpUserService.getFtpadmin();
			String home = user.getHomedirectory();
			File dir = new File(home, recvxmlDir);
			if (!dir.isDirectory()) {
				status.setMsg(dir.getAbsolutePath() + "不是一个文件夹。");
				status.setSuccess(false);
				return status;
			}
			File[] filexmls = dir.listFiles();
			if (filexmls == null || filexmls.length <= 0) {
				logger.info(dir.getAbsolutePath() + "下没有文件需要解析");
				status.setSuccess(true);
				status.setMsg(dir.getAbsolutePath() + "下没有文件需要解析");
				return status;
			}
			for (File filexml : filexmls) {
				try {
					if (!checkFilename(filexml)) {
						continue;//非xml文件不解析
					}
					SendFileData sendFileData =XstreamUtil.toObject(SendFileData.class,filexml);
					RecvFileData recvFileData = new RecvFileData();
					BeanMapper.copy(sendFileData, recvFileData);
					//初始化接收记录
					recvFileData.setModified(new Date());

					String to = recvFileData.getRecvAdaptorcode();
					FtpUser touser = ftpUserService.get(to);

					String[] attachements = recvFileData.getFilepaths().split(";");
					String[] storepaths = recvFileData.getStorepaths().split(";");

					File recvmetadir = new File(new File(touser.getHomedirectory(), recvmetadataDir),
							recvFileData.getSendNodecode());
//						recvmetadir = new File(recvmetadir,to);
					
					recvFileData.setFilehome(recvmetadir.getAbsolutePath());
					Posthead posthead=XstreamUtil.toObject(Posthead.class, recvFileData.getPosthead());
					
					//解密处理
					EncryptService encryptService = EncryptServiceFactory.createEncryptService(ENCRYPT_ALGORITHM.DES);
					//解压缩
					CompressService compressService = CompressServiceFactory.createCompressService(COMPRESS_ALGORITHM.JAVA_GZIP);
					List<ProcessInfo> list=posthead.getProcesses().getProcess();
					
					for (int i = 0; i < attachements.length; i++) {
						
						File file = new File(new File(home, recvmetadataDir), storepaths[i]);//存储文件
						File fileto = new File(recvmetadir, attachements[i]);
						File parent = fileto.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							FileUtils.copyFile(file, fileto);//复制文件，将file拷贝到fileto中
							
							//对fileto进行解密和解压缩
                             //解密处理
							String encrypt=list.get(0).getEncrypt();
							if (encrypt.equals("1")) {//解密
								String seed=encryptService.randomSeed(posthead.getFrom().getNodecode()+posthead.getFrom().getAdaptorcode());
								File encryptFile=new File(fileto.getParentFile(),list.get(i).getEncryptfile());//加密文件名称
								fileto.renameTo(encryptFile);
								String enpcryptpath=encryptService.decryptFile(seed, encryptFile.getAbsolutePath(),true);
								logger.info("[remoteStore]解密后的文件是"+enpcryptpath);
								fileto=new File(enpcryptpath);//解密后的文件
							}
							
							//解压缩处理 复制文件后进行 解压缩处理，一一对应
							String compress=list.get(i).getCompress();//得到对应的压缩信息
							if (compress.equals("1")) {//解压缩fileto文件
								File tarFile=new File(fileto.getParentFile(), list.get(i).getCompressfile());
								fileto.renameTo(tarFile);//还原成.gz文件
								String path=compressService.uncompress(tarFile,true);
								fileto=new File(path);
								logger.info("[remoteStore]解压后的文件是:"+path);
								fileto.renameTo(new File(recvmetadir, attachements[i]));//还原文件名
							}
						}
					}
					//路由更新需要读取原来传来的信息
					Date now = new Date();
					msg = "远程落地成功";
					status.setSuccess(true);
					status.setMsg(msg);
					recvFileData.setSendStatus(AppConst.SendStatus.REMOTE_READY.value());
					RouteLog.setRemoteStore(recvFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
					recvFileDataService.insertOrUpdate(recvFileData);//存数据库
					//创建响应文件,路由1
					File file =new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_1.getOrder() + ".xml");
					File parent = file.getParentFile();
					if (filexml.delete() && (parent.exists() || parent.mkdirs())) {
						XstreamUtil.toXmlfile(recvFileData, file);
					}
				} catch (Exception e) {
					logger.error("[remoteStore]执行远程落地时发生异常：" + e.getMessage());
				}
			}
		} catch (Exception e) {
			msg = "远程落地--检查FTP文件失败，" + e.fillInStackTrace();
			logger.error("执行完毕remoteStore()" + msg, e);
			status.setSuccess(false);
			status.setMsg(msg);
			return status;
		}
		logger.info("执行完毕remoteStore。");
		return null;
	}

	
	
	
	/**
	 * 第4步：通知接收人
	 */
	@Override
	public Status notifyReceiver() {
		logger.info("进入方法notifyReceiver。");
		List<RecvFileData> successDataList = new ArrayList<RecvFileData>(); //往管道发送成功的数据
		List<RecvFileData> resendDataList = new ArrayList<RecvFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<RecvFileData> failDataList = new ArrayList<RecvFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			//获取接收为接收的文件，状态为发送状态等于发送中
			List<RecvFileData> unsentList = recvFileDataService.getUnsentList();
			Status status = Status.getInstance();
			String msg = "";
			Date now = new Date();
			if (CollectionUtil.hasElement(unsentList)) {
				for (RecvFileData fileData : unsentList) {
					msg = "数据发送至适配器成功";
					fileData.setSendStatus(AppConst.SendStatus.REMOTE_SENDING.value());
					fileData.setModified(new Date());
					RouteLog.setRemoteSys(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				status = this.updateRemoteSendStatus(unsentList, AppConst.SendStatus.REMOTE_SENDING.value());
				if (!status.isSuccess()) {
					msg = "数据发送至适配器失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}
				for (RecvFileData recvFileData : unsentList) {
					try {
						
						if (recvFileData.getRecvAdaptorcode().equals(NodeExchTestService.TEST_ADAPTER_CODE)) {//如果是测试的话，直接成功
							RouteLog.setRemoteSys(recvFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
							File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
							File parent = file.getParentFile();
							if (parent.exists() || parent.mkdirs()) {
								recvFileData.setReciverSigned("ok");
								recvFileData.setSendStatus(AppConst.SendStatus.SENT.value());//发送成功
								recvFileData.setModified(new Date());
								logger.info("[FileDataExchageLifecycleImp.notifyReceiver]落地成文件"+file.getAbsolutePath()+",该文件是否存在"+file.exists()+",存在文件的最后更新日期："+file.lastModified());
								XstreamUtil.toXmlfile(recvFileData, file);
								logger.info("[FileDataExchageLifecycleImp.notifyReceiver]落地成文件"+file.getAbsolutePath()+"成功,成功后的文件最后更新日期:"+file.lastModified());
								successDataList.add(recvFileData);
							}
							continue;
						}
						
						logger.info("notifyReceiver将会落地成文件"+recvFileData.getOrderId());
						//将发送状态修改为发送中，并更新相关的路由日志
						AdapterInfo adapterInfo=baseInfoService.getAdapterInfo(recvFileData.getRecvNodecode(), recvFileData.getRecvAdaptorcode());
						if (adapterInfo==null || "".equals(adapterInfo.getWsdlUrl()) ) {
							msg = "发送给接收适配器失败,根据系统编码["+recvFileData.getRecvNodecode()+"]和适配器编码["+recvFileData.getSendAdaptorcode()+"]并未找到适配器";
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(recvFileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								RouteLog.setRemoteSys(recvFileData, AppConst.NO, expiredStatus.getMsg()+"  "+msg, AppConst.dtFormat.format(new Date()));//更新路由状态
								recvFileData.setSendStatus(AppConst.SendStatus.FAIL.value());//发送失败
								recvFileData.setModified(new Date());
								//更新交换信息,路由2
								File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(recvFileData, file);
									failDataList.add(recvFileData);
								}
							}else{//重新发送
								recvFileData.setModified(new Date());
								RouteLog.setRemoteSys(recvFileData, AppConst.NO, "消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(new Date()));//更新路由状态
								recvFileData.setSendStatus( AppConst.SendStatus.REMOTE_READY.value());
								
								//更新交换信息
								File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(recvFileData, file);
									resendDataList.add(recvFileData);
								}
							}
							continue;
						}
						
						String address = adapterInfo.getWsdlUrl();
						String resps=null;
						try {
							HttpDataExchRecvService client=new HttpDataExchRecvService(address);
                            Posthead formmatPosthead=this.formatt(XstreamUtil.toObject(Posthead.class, recvFileData.getPosthead()), recvFileData.getRecvNodecode(), recvFileData.getRecvAdaptorcode());
						    
                            logger.info("[notifyReceiver]请求["+recvFileData.getOrderId()+"]将通知适配器，适配器地址["+address+"]");
						    
							resps = client.receiveFileMsg(XstreamUtil.toXml(formmatPosthead),
									recvFileData.getMetaData(),JsonUtil.toObjectList(recvFileData.getFileItems(), String.class));
							logger.info("[notifyReceiver]请求["+recvFileData.getOrderId()+"]通知适配器成功，相应信息["+resps+"]");
						} catch (Exception e) {
							logger.info("[notifyReceiver]请求["+recvFileData.getOrderId()+"]通知适配器失败，失败信息,"+e);
							msg = "发送给接收适配器失败,错误原因"+e.getMessage();
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(recvFileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								RouteLog.setRemoteSys(recvFileData, AppConst.NO,expiredStatus.getMsg()+"  "+ msg, AppConst.dtFormat.format(new Date()));//更新路由状态
								recvFileData.setSendStatus(AppConst.SendStatus.FAIL.value());//发送失败
								recvFileData.setModified(new Date());
								
								//更新交换信息,路由2
								File file = new File(globalToSendrespDir, recvFileData.getOrderId() +AppConst.RouteOrder.ROUTE_2.getOrder()+ ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(recvFileData, file);
									failDataList.add(recvFileData);
								}
							}else{//重新发送
								recvFileData.setModified(new Date());
								RouteLog.setRemoteSys(recvFileData, AppConst.NO, "消息已重发，重发原因["+msg+"]", AppConst.dtFormat.format(new Date()));//更新路由状态
								recvFileData.setSendStatus( AppConst.SendStatus.REMOTE_READY.value());
								
								//更新交换信息
								File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(recvFileData, file);
									resendDataList.add(recvFileData);
								}
							}
							continue;
						}
						RouteLog.setRemoteSys(recvFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
						File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
						File parent = file.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							recvFileData.setReciverSigned(resps);
							recvFileData.setSendStatus(AppConst.SendStatus.SENT.value());//发送成功
							recvFileData.setModified(new Date());
							logger.info("[FileDataExchageLifecycleImp.notifyReceiver]落地成文件"+file.getAbsolutePath()+",该文件是否存在"+file.exists()+",存在文件的最后更新日期："+file.lastModified());
							XstreamUtil.toXmlfile(recvFileData, file);
							logger.info("[FileDataExchageLifecycleImp.notifyReceiver]落地成文件"+file.getAbsolutePath()+"成功,成功后的文件最后更新日期:"+file.lastModified());
							successDataList.add(recvFileData);
						}
					} catch (Exception e) {
						msg = "数据发送至适配器失败：" + e.getMessage();
						recvFileData.setModified(new Date());
						recvFileData.setSendStatus( AppConst.SendStatus.FAIL.value());
						RouteLog.setRemoteSys(recvFileData, AppConst.NO, msg, AppConst.dtFormat.format(now));//更新路由状态
						File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
						File parent = file.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							try {
								XstreamUtil.toXmlfile(recvFileData, file);
							} catch (Exception e2) {
								logger.error("[FileDataExchageLifecycleImp.notifyReceiver]生成" + file + "回执文件发生异常：" + e2.getMessage());
							}
						}
						failDataList.add(recvFileData);
						logger.error("[notifyReceiver]数据发送至适配器失败" + msg);
					}
				}
			}
		} catch (NiceException e) {
			logger.error("[notifyReceiver]数据发送至适配器失败", e);
		} catch (Exception e) {
			logger.error("[notifyReceiver]数据发送至适配器失败", e);
		} finally {
			this.updateRemoteSendStatus(successDataList, AppConst.SendStatus.SENT.value()); //发送成功
			this.updateRemoteSendStatus(resendDataList, AppConst.SendStatus.REMOTE_READY.value()); //等待重发
			this.updateRemoteSendStatus(failDataList, AppConst.SendStatus.FAIL.value()); //发送失败
		}
		logger.info("执行完毕notifyReceiver。");
		return null;
	}

	
	public void processLost(){
		List<RecvFileData> list;
		try {
			list = recvFileDataService.getProcessLost();
			for (RecvFileData recvFileData : list) {
				//路由2
				File file = new File(globalToSendrespDir, recvFileData.getOrderId()+AppConst.RouteOrder.ROUTE_2.getOrder() + ".xml");
				File parent = file.getParentFile();
				if (parent.exists() || parent.mkdirs()) {
					try {
						XstreamUtil.toXmlfile(recvFileData, file);
					} catch (IOException e) {
						continue;
					}
				}
			}
		} catch (ServiceException e) {
			logger.error(e);
		}
	}
	/*
	第5步：把远端的响应文件发送到发送系统（这样发送系统能更新远端接收状态）
	 */

	@Override
	public Status sendRemoteResp() {
		logger.info("进入方法sendRemoteResp。");
		Status status = Status.getInstance();
		File dir = new File(globalToSendrespDir);
		if (!dir.isDirectory()) {
			status.setMsg(dir.getAbsolutePath() + "不是一个文件夹。");
			status.setSuccess(false);
			return status;
		}
		File[] filexmls = dir.listFiles(new FileFilter() {
			
			@Override
			public boolean accept(File pathname) {
				if(pathname.getName().endsWith(".xml")) return true;//只解析.xml文件
				return false;
			}
		});
		
		if (filexmls == null || filexmls.length <= 0) {
			logger.info("[sendRemoteResp]" + dir.getAbsolutePath() + "下没有文件需要发送");
			status.setSuccess(true);
			status.setMsg(dir.getAbsolutePath() + "下没有文件需要发送");
			return status;
		}
		logger.info("排序之前的文件名称"+fileArrayNames(filexmls));
		Arrays.sort(filexmls, new Comparator<File>() {
			@Override
			public int compare(File o1, File o2) {
				if (o1.lastModified()>o2.lastModified()) {
					return 1;
				}else if(o1.lastModified()<o2.lastModified()){
					return -1;
				}else{
					return o1.getName().compareTo(o2.getName());
				}
			}
		});
		logger.info("排序之后的文件名称"+fileArrayNames(filexmls));
		//todo ----------------------------
		for (File filexml : filexmls) {
			long lastModified=filexml.lastModified();
			logger.info("[sendRemoteResp]要发送的文件"+filexml.getAbsolutePath()+"此时文件最后更新的日期:"+filexml.lastModified());
			logger.info("[sendRemoteResp]--------------------------"+filexml.getAbsolutePath()+"-开始上传----------");
			if (!checkFilename(filexml) || existTmpFile(filexmls, filexml)) {
				continue;//非xml不解析
			}
			
			RecvFileData recvFileData = null;
			try {
				recvFileData = XstreamUtil.toObject(RecvFileData.class,filexml);
				logger.info("[sendRemoteResp]要发送的文件"+filexml.getAbsolutePath()+"转换成对象成功"+"此时文件最后更新的日期:"+filexml.lastModified());
			} catch (Exception e1) {
				logger.error("[sendRemoteResp] 文件["+filexml+"]解析失败"+e1);
				long last=filexml.lastModified();
				if (lastModified==last) {
					logger.info("[sendRemoteResp]文件"+filexml.getAbsolutePath()+"解析失败了，该文件为无效文件，删除了");
					filexml.delete();
				}
				continue;//继续下一个循环
			}
			String nodecode = null;//获取发送方的nodecode
			if (NodeInfoParam.isInnerNode()) {//如果是内网
				if(recvFileData.getCrossNet().equals(AppConst.CrossNetType.SAME_NETWORK.value())){//如果同网段
					nodecode=recvFileData.getSendNodecode();
				}else if(recvFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK.value())){//外网到内网
					nodecode=recvFileData.getInnerGapNodeCode();
				}
			}else{//如果是外网
				if(recvFileData.getCrossNet().equals(AppConst.CrossNetType.SAME_NETWORK.value()) || recvFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK.value())){//如果同网段
					nodecode=recvFileData.getSendNodecode();
				}else{//内网到外网，刻盘以后的
					nodecode=recvFileData.getOutGapNodeCode();
				}
			}
			PipeLineFtp ftp = null;
			try {
				ftp = distributedNodeInfoService.getFtpPipeLineByNodeCode(nodecode);
			} catch (ServiceException e) {
				logger.error("[sendRemoteResp]获取ftp信息发生异常：" + e.getMessage());
				continue;
			}
			String host = ftp.getIp();//发送目的服务器的地址
			String tousername = AppConst.EMBFTP.EMBFTP_ADMIN_USERID;//发送目的服务器的ftp用户名
			String topassword;
			try {
				topassword = AppConst.EMBFTP.EMBFTP_ADMIN_PWD+" "+tousername+" "+AppConst.getAdminAuthCode();
				String tolocalresp = File.separator + remoterespDir;//ftp传输路径
				int port = ftp.getPort();
				tolocalresp += File.separator + filexml.getName();
				logger.info("[sendRemoteResp]即将发送的文件"+filexml.getAbsolutePath());
				status = this.uploadXml(host, tousername, topassword, port, filexml, tolocalresp);
				if (status.isSuccess()) {
					logger.info("[sendRemoteResp]--------------------------"+filexml.getAbsolutePath()+" 上传成功，状态为"+recvFileData.getSendStatus()+"----------");
					
					long last=filexml.lastModified();
					if (lastModified==last) {
						logger.info("[sendRemoteResp]文件 "+filexml.getAbsolutePath()+" 删除了,last的值:"+last+",删除的最后更新日期:"+filexml.lastModified());
						filexml.delete();
						logger.info("[sendRemoteResp]删除后："+filexml.getAbsolutePath()+" 是否存在："+filexml.exists()+",文件最后更新时间"+filexml.lastModified());
					}else{
						logger.info("[sendRemoteResp]文件 "+filexml.getAbsolutePath()+" 不需删除，读时间"+lastModified+",删时最后时间"+last);
					}
				}else{
					logger.info("[sendRemoteResp]--------------------------"+filexml.getAbsolutePath()+"-开始上传失败，状态为"+recvFileData.getSendStatus()+"----------"+status.getMsg());
				}
			} catch (Exception e) {
				logger.error(e);
			}//发送目的服务器的ftp密码
		}
		logger.info("执行完毕sendRemoteResp。");
		return null;
	}

	/**
	 * 第6步：解析远端状态。跟新发送列表的信息
	 */
	@Override
	public Status parseRemoteResp() {
		logger.info("进入方法parseRemoteResp。");
		String msg = "";
		Status status = Status.getInstance();
		try {
			FtpUser user = ftpUserService.getFtpadmin();
			String home = user.getHomedirectory();
			File dir = new File(home, remoterespDir);
			if (!dir.isDirectory()) {
				status.setMsg(dir.getAbsolutePath() + "不是一个文件夹。");
				status.setSuccess(false);
				return status;
			}
			File[] filexmls = dir.listFiles(new FileFilter() {
				@Override
				public boolean accept(File pathname) {
					if(pathname.getName().endsWith(".xml")) return true;//只解析.xml文件
					return false;
				}
			});
			
			
			if (filexmls == null || filexmls.length <= 0) {
				logger.info("[parseRemoteResp]" + dir.getAbsolutePath() + "下没有文件需要解析");
				status.setSuccess(true);
				status.setMsg(dir.getAbsolutePath() + "下没有文件需要解析");
				return status;
			}
			logger.info("排序之前的文件名称"+fileArrayNames(filexmls));
			Arrays.sort(filexmls, new Comparator<File>() {
				@Override
				public int compare(File o1, File o2) {
					if (o1.lastModified()>o2.lastModified()) {
						return 1;
					}else if(o1.lastModified()<o2.lastModified()){
						return -1;
					}else{//比较字符串的大小，按照acsii值比较
						return o1.getName().compareTo(o2.getName());
					}
				}
			});
			logger.info("排序之后的文件名称"+fileArrayNames(filexmls));
			for (File filexml : filexmls) {
				try {
					long lastModified=filexml.lastModified();
					logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】开始解析...........");
					if (!checkFilename(filexml) || existTmpFile(filexmls, filexml)) {
						logger.info("[parseRemoteResp]非xml文件");
						continue;//非xml不解析
					}
					
					//todo ----------------------------
					RecvFileData recvFileData = null;
					try {
						recvFileData = XstreamUtil.toObject(RecvFileData.class,filexml);
					} catch (Exception e1) {
						logger.error("[parseRemoteResp]文件["+filexml+"]解析失败"+e1);
						System.err.println("[parseRemoteResp] 文件["+filexml+"]解析失败"+e1);
						long last=filexml.lastModified();
						if (lastModified==last) {
							logger.info("[parseRemoteResp] 文件"+filexml.getAbsolutePath()+"解析失败了，该文件为无效文件，删除了");
							filexml.delete();
						}
						continue;//继续下一个循环
					}
					String orderId = recvFileData.getOrderId();
					logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中...........发送状态为:"+recvFileData.getSendStatus());
					if (!NodeInfoParam.isInnerNode()) {//如果是外网
						logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中...........外网发送状态为:"+recvFileData.getSendStatus());
						SendFileData sendFileData = sendFileDataService.get(orderId);
						if (sendFileData == null) {
							logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中...........外网发送状态为:"+recvFileData.getSendStatus()+"==sendFileData为null");
							long last=filexml.lastModified();
							if (lastModified==last) {
								logger.info("[parseRemoteResp]文件"+filexml.getAbsolutePath()+"解析成功，但是无法根据"+orderId+"找到对应记录，该文件为无效文件，删除了");
								filexml.delete();
							}
							continue;
						}
						BeanMapper.copy(recvFileData, sendFileData);
						sendFileDataService.update(sendFileData);
						logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中,更新后的状态{"+sendFileData.getSendStatus()+"},更新后的路由{"+sendFileData.getRoutelog()+"}");
						SendFileData sendFileData1 = sendFileDataService.get(orderId);
						logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析完,【"+orderId+"】重新从数据库中获取{"+sendFileData1.getSendStatus()+"},更新后的路由{"+sendFileData1.getRoutelog()+"}");
					}else{//如果是内网
						if(recvFileData.getCrossNet().equals(AppConst.CrossNetType.SAME_NETWORK.value()) || (recvFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK.value()) && recvFileData.getThroughGap().equals("2"))){//如果同网段
							logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中...........内网同网段发送状态为:"+recvFileData.getSendStatus());
							
							SendFileData sendFileData = sendFileDataService.get(orderId);
							if (sendFileData == null) {
								logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中..........内网同网段发送状态为:"+recvFileData.getSendStatus()+"==sendFileData为null");
								long last=filexml.lastModified();
								if (lastModified==last) {
									logger.info("[parseRemoteResp]文件"+filexml.getAbsolutePath()+"解析成功，但是无法根据"+orderId+"找到对应记录，该文件为无效文件，删除了");
									filexml.delete();
								}
								continue;
							}
							BeanMapper.copy(recvFileData, sendFileData);
							sendFileDataService.update(sendFileData);
						}else if(recvFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK.value()) && !recvFileData.getThroughGap().equals("2")){//外网到内网
							logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析中...........外网到内网发送状态为:"+recvFileData.getSendStatus());
							
							CrossNetTmpFileData crossNetTmpFileData = crossNetTmpFileDataService.get(orderId);
							if (crossNetTmpFileData == null) {
								long last=filexml.lastModified();
								if (lastModified==last) {
									logger.info("[parseRemoteResp]文件"+filexml.getAbsolutePath()+"解析成功，但是无法根据"+orderId+"找到对应记录，该文件为无效文件，删除了");
									filexml.delete();
								}
								continue;
							}
							BeanMapper.copy(recvFileData, crossNetTmpFileData);
							crossNetTmpFileDataService.update(crossNetTmpFileData);
						}
					}
					logger.info("[parseRemoteResp]文件【"+filexml.getAbsolutePath()+"】解析完成...........将删除");
					long last=filexml.lastModified();
					if (lastModified==last) {
						logger.info("[parseRemoteResp]文件"+filexml.getAbsolutePath()+"删除了");
						filexml.delete();
					}else{
						logger.info("[parseRemoteResp]文件"+filexml.getAbsolutePath()+"不需删除，读时间"+lastModified+",删时最后时间"+last);
					}
				} catch (Exception e) {
					logger.error("parseRemoteResp发生异常：" + e.getMessage());
				}
			}
		} catch (ServiceException e) {
			msg = "更新本地路由信息失败" + e.fillInStackTrace();
			status.setSuccess(false);
			status.setMsg(msg);
			logger.info("执行完毕parseRemoteResp，发生异常：" + msg);
			return status;
		}
		logger.info("执行完毕parseRemoteResp。");
		return null;
	}

	/**
	 * 第7步：通知发送者
	 */
	@Override
	public Status notifySender() {
		logger.info("[FileDataExchageLifecycleImp]进入方法notifySender()");
		List<SendFileData> successDataList = new ArrayList<SendFileData>(); //往管道发送成功的数据
		List<SendFileData> resendDataList = new ArrayList<SendFileData>(); //待重发的数据，管道发送失败时将进行重发
		List<SendFileData> failDataList = new ArrayList<SendFileData>(); //发送失败的数据，只要这条消息符合失效的策略，则判定发送失败
		try {
			//获取接收为接收的文件，状态为发送状态等于发送中
			List<SendFileData> unsentList = sendFileDataService.getUnnotifyList();
			logger.info("[FileDataExchageLifecycleImp]需要通知发送适配器的数量为：" + unsentList.size());
			Status status = Status.getInstance();
			String msg = "";
			Date now = new Date();
			if (CollectionUtil.hasElement(unsentList)) {
				for (SendFileData fileData : unsentList) {
					msg = "通知发送适配器成功";
					fileData.setNotifyStatus(AppConst.NotifyStatus.NOTIFYING.value());
					fileData.setModified(new Date());
					logger.info("[FileDataExchageLifecycleImp]通知发送适配器成功，设置路由状态为通知成功。");
					RouteLog.setLocalSys(fileData, AppConst.YES, msg, AppConst.dtFormat.format(now));
				}
				status = this.updateLocalNotityStatus(unsentList, AppConst.NotifyStatus.NOTIFYING.value());
				if (!status.isSuccess()) {
					logger.info("[FileDataExchageLifecycleImp]通知发送适配器失败：" + status.getMsg());
					msg = "通知发送适配器失败：" + status.getMsg();
					status.setSuccess(false);
					status.setMsg(msg);
					return status;
				}
				for (SendFileData sendFileData : unsentList) {
					logger.info("notifySender,开始执行orderid["+sendFileData.getOrderId()+"],路由信息{"+sendFileData.getRoutelog()+"}");
					if (sendFileData.getSendAdaptorcode().equals(NodeExchTestService.TEST_ADAPTER_CODE)) {
						RouteLog.setLocalSys(sendFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
						sendFileData.setSenderSigned("ok");
						sendFileData.setNotifyStatus(AppConst.NotifyStatus.NOTIFIED.value());//发送成功
						logger.info("[FileDataExchageLifecycleImp]通知适配器成功，更改状态为：" + AppConst.NotifyStatus.NOTIFIED.value());
						sendFileData.setModified(new Date());
						File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
						File parent = file.getParentFile();
						if (parent.exists() || parent.mkdirs()) {
							XstreamUtil.toXmlfile(sendFileData, file);//生成回执文件
						}
						successDataList.add(sendFileData);
						continue;
					}
					
					String routeLogXml = sendFileData.getRoutelog();
					RouteLog routeLog = XstreamUtil.toObject(RouteLog.class,routeLogXml);
					try {
						//将发送状态修改为发送中，并更新相关的路由日志
						AdapterInfo  sendAdapterInfo = baseInfoService.getAdapterInfo(sendFileData.getSendNodecode(), sendFileData.getSendAdaptorcode());//baseInfoService.getSysServiceInfoBySysCode(syscode);
						if (sendAdapterInfo==null || "".equals(sendAdapterInfo.getWsdlUrl()) ) {
							msg = "通知发送适配器失败,根据系统编码["+sendFileData.getSendNodecode()+"]和适配器编码["+sendFileData.getSendAdaptorcode()+"]并未找到适配器";
							logger.info("[FileDataExchageLifecycleImp]" + msg);
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(sendFileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								RouteLog.setLocalSys(sendFileData, AppConst.NO, expiredStatus.getMsg()+"  "+msg, AppConst.dtFormat.format(now));//更新路由状态
								sendFileData.setNotifyStatus(AppConst.NotifyStatus.FAIL.value());//发送失败
								sendFileData.setModified(new Date());
								logger.info("[FileDataExchageLifecycleImp]消息过期，更改状态为：" + AppConst.NotifyStatus.FAIL.value());
								//更新交换
								if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
									RecvFileData recvFileData = new RecvFileData();
									BeanMapper.copy(sendFileData, recvFileData);
									recvFileDataService.insertOrUpdate(recvFileData);
								} else {
									if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
											&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
										//路由3
										File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
										File parent = file.getParentFile();
										if (parent.exists() || parent.mkdirs()) {
											XstreamUtil.toXmlfile(sendFileData, file);
										}
									}
								}
								logger.info("[FileDataExchageLifecycleImp]消息过期，加入失败列表。");
								failDataList.add(sendFileData);
							}else{
								RouteLog.setLocalSys(sendFileData, AppConst.NO, "消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(now));//更新路由状态
								sendFileData.setNotifyStatus(AppConst.NotifyStatus.READY.value());//待通知
								sendFileData.setModified(new Date());
								logger.info("[FileDataExchageLifecycleImp]消息已重发，重发状态更改为：" + AppConst.NotifyStatus.READY.value());
								//更新交换
								if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
									RecvFileData recvFileData=new RecvFileData();
									BeanMapper.copy(sendFileData, recvFileData);
									recvFileDataService.insertOrUpdate(recvFileData);
								} else {
									if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
											&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
										File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder()+ ".xml");
										File parent = file.getParentFile();
										if (parent.exists() || parent.mkdirs()) {
											XstreamUtil.toXmlfile(sendFileData, file);
										}
									}
								}
								logger.info("[FileDataExchageLifecycleImp]消息重发，加入重发列表。");
								resendDataList.add(sendFileData);
							}
							continue;
						}
						String address = sendAdapterInfo.getWsdlUrl();
						String resps=null;
						try {
							logger.info("[FileDataExchageLifecycleImp]通知发送适配器,开始发送至" + address);
							HttpDataExchRecvService client=new HttpDataExchRecvService(address);
							resps = client.receiveFileNotify(sendFileData.getGroupId(), sendFileData.getOrderId(),
									AppConst.SendStatus.SENT.value().equals(sendFileData.getSendStatus())?"1":"0", sendFileData.getReciverSigned(),
											sendFileData.getMetaData());
						} catch (Exception e) {
							msg = "通知发送适配器失败,错误信息:"+e.getMessage();
							logger.info("[FileDataExchageLifecycleImp]通知发送适配器失败,发生异常：" + msg);
							//判断消息是否过期
							Status expiredStatus = timeoutExpiredStrategy.isExpired(sendFileData.getCreated());
							if (expiredStatus.isSuccess()) {//如果过期则发送失败
								RouteLog.setLocalSys(sendFileData, AppConst.NO, expiredStatus.getMsg()+"  "+msg, AppConst.dtFormat.format(now));//更新路由状态
								sendFileData.setNotifyStatus(AppConst.NotifyStatus.FAIL.value());//发送失败
								sendFileData.setModified(new Date());
								logger.info("[FileDataExchageLifecycleImp]消息过期，更改状态为：" + AppConst.NotifyStatus.FAIL.value());
								//更新交换
								if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
									RecvFileData recvFileData=new RecvFileData();
									BeanMapper.copy(sendFileData, recvFileData);
									recvFileDataService.insertOrUpdate(recvFileData);
								} else {
									if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
											&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
										File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
										File parent = file.getParentFile();
										if (parent.exists() || parent.mkdirs()) {
											XstreamUtil.toXmlfile(sendFileData, file);
										}
									}
								}
								failDataList.add(sendFileData);
							} else {
								RouteLog.setLocalSys(sendFileData, AppConst.NO, "消息已重发，重发原因<<"+msg+">>", AppConst.dtFormat.format(now));//更新路由状态
								sendFileData.setNotifyStatus(AppConst.NotifyStatus.READY.value());//发送失败
								sendFileData.setModified(new Date());
								logger.info("[FileDataExchageLifecycleImp]消息已重发，重发状态更改为：" + AppConst.NotifyStatus.READY.value());
								//更新交换
								if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
									RecvFileData recvFileData=new RecvFileData();
									BeanMapper.copy(sendFileData, recvFileData);
									recvFileDataService.insertOrUpdate(recvFileData);
								}else{
									if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
											&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
										File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
										File parent = file.getParentFile();
										if (parent.exists() || parent.mkdirs()) {
											XstreamUtil.toXmlfile(sendFileData, file);
										}
									}
								}
								resendDataList.add(sendFileData);
							}
							continue;
						}
						logger.info("[FileDataExchageLifecycleImp]发送至" + address + ",返回消息：" + resps);
						RouteLog.setLocalSys(sendFileData, AppConst.YES, msg, AppConst.dtFormat.format(now));//更新路由状态
						sendFileData.setSenderSigned(resps);
						sendFileData.setNotifyStatus(AppConst.NotifyStatus.NOTIFIED.value());//发送成功
						logger.info("[FileDataExchageLifecycleImp]通知适配器成功，更改状态为：" + AppConst.NotifyStatus.NOTIFIED.value());
						sendFileData.setModified(new Date());
						if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
							RecvFileData recvFileData=new RecvFileData();
							BeanMapper.copy(sendFileData, recvFileData);
							recvFileDataService.insertOrUpdate(recvFileData);
						}else{
							if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
									&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
								File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(sendFileData, file);//生成回执文件
								}
							}
						}
						logger.info("notifySender,通知成功后orderid["+sendFileData.getOrderId()+"],路由信息{"+sendFileData.getRoutelog()+"},最后更新时间"+AppConst.dtFormat.format(sendFileData.getModified()));
						SendFileData s=sendFileDataService.get(sendFileData.getOrderId());
						logger.info("notifySender,通知成功后从数据库中重新获取：orderid["+s.getOrderId()+"],路由信息{"+s.getRoutelog()+"},最后更新时间"+AppConst.dtFormat.format(s.getModified()));
						successDataList.add(sendFileData);
					} catch (Exception e) {
						logger.error("[FileDataExchageLifecycleImp]通知发送适配器失败:" + e.getMessage());
						msg = "通知发送适配器失败" + e.getMessage();
						RouteLog.setLocalSys(sendFileData, AppConst.NO, msg, AppConst.dtFormat.format(now));//更新路由状态
						sendFileData.setNotifyStatus(AppConst.NotifyStatus.FAIL.value());//发送失败
						sendFileData.setModified(new Date());
						if (sendFileData.getCrossNode().equals(AppConst.NO) && !sendFileData.getCrossNet().equals(AppConst.CrossNetType.OUT_INNER_NETWORK)) {
							RecvFileData recvFileData=new RecvFileData();
							BeanMapper.copy(sendFileData, recvFileData);
							recvFileDataService.insertOrUpdate(recvFileData);
						}else{
							if (routeLog.getLocalPipeline() != null && routeLog.getLocalPipeline().getStatus() != null
									&& routeLog.getLocalPipeline().getStatus().equals(AppConst.YES)) {
								File file = new File(globalToRecvrespDir, sendFileData.getOrderId()+AppConst.RouteOrder.ROUTE_3.getOrder() + ".xml");
								File parent = file.getParentFile();
								if (parent.exists() || parent.mkdirs()) {
									XstreamUtil.toXmlfile(sendFileData, file);
								}
							}
						}
						failDataList.add(sendFileData);
						logger.error("通知适配器失败", e);
					}
				}
			}
		} catch (NiceException e) {
			logger.error("通知发送适配器失败", e);
		} catch (Exception e) {
			logger.error("通知发送适配器失败", e);
		} finally {
			this.updateLocalNotityStatus(successDataList, AppConst.NotifyStatus.NOTIFIED.value()); //发送成功
			this.updateLocalNotityStatus(resendDataList, AppConst.NotifyStatus.READY.value()); //等待重发
			this.updateLocalNotityStatus(failDataList, AppConst.NotifyStatus.FAIL.value()); //发送失败
			for (SendFileData sendFileData2 : successDataList) {
				SendFileData s;
				try {
					s = sendFileDataService.get(sendFileData2.getOrderId());
					logger.info("notifySender,执行完finally后,通知成功后从数据库中重新获取：orderid["+s.getOrderId()+"],路由信息{"+s.getRoutelog()+"},最后更新时间"+AppConst.dtFormat.format(s.getModified()));
				} catch (ServiceException e) {
					e.printStackTrace();
				}
				
			}
			logger.info("[FileDataExchageLifecycleImp]执行完毕notifySender()，更新本地通知状态。");
		}
		logger.info("[FileDataExchageLifecycleImp]执行完毕notifySender()。");
		return null;
	}

	/**
	 * 第8步：把本地的响应发送到远端。为了更新远端的（通知发送者状态）
	 */
	@Override
	public Status sendLocalResp() {
		logger.info("进入方法sendLocalResp。");
		Status status = Status.getInstance();
		File dir = new File(globalToRecvrespDir);
		if (!dir.isDirectory()) {
			status.setSuccess(false);
			status.setMsg(dir.getAbsolutePath() + "不是一个文件夹。");
			return status;
		}
		File[] filexmls = dir.listFiles(new FileFilter() {
			@Override
			public boolean accept(File pathname) {
				if(pathname.getName().endsWith(".xml")) return true;//只解析.xml文件
				return false;
			}
		});
		
		if (filexmls == null || filexmls.length <= 0) {
			logger.info("[sendLocalResp]" + dir.getAbsolutePath() + "下没有文件需要发送");
			status.setSuccess(true);
			status.setMsg(dir.getAbsolutePath() + "下没有文件需要发送");
			return status;
		}
		logger.info("排序之前的文件名称"+fileArrayNames(filexmls));
		Arrays.sort(filexmls, new Comparator<File>() {
			@Override
			public int compare(File o1, File o2) {
				if (o1.lastModified()>o2.lastModified()) {
					return 1;
				}else if(o1.lastModified()<o2.lastModified()){
					return -1;
				}else{
					return o1.getName().compareTo(o2.getName());
				}
			}
		});
		logger.info("排序之后的文件名称"+fileArrayNames(filexmls));
		for (File filexml : filexmls) {
			try {
				if (!checkFilename(filexml) || existTmpFile(filexmls, filexml)) {
					continue;//非xml不解析
				}
				long lastModified=filexml.lastModified();
				SendFileData sendFileData = null;
				try {
					sendFileData = XstreamUtil.toObject(SendFileData.class,filexml);
				} catch (Exception e1) {
					logger.error("[sendLocalResp]文件["+filexml+"]解析失败"+e1);
					long last=filexml.lastModified();
					if (lastModified==last) {
						logger.info("sendLocalResp 文件"+filexml.getAbsolutePath()+"解析失败了，该文件为无效文件，删除了");
						filexml.delete();
					}
					continue;//继续下一个循环
				}
				String nodecode = sendFileData.getRecvNodecode();
				PipeLineFtp ftp = null;
				try {
					ftp = distributedNodeInfoService.getFtpPipeLineByNodeCode(nodecode);
				} catch (ServiceException e) {
					logger.error("[sendLocalResp]获取ftp信息发生异常：" + e.getMessage());
					continue;
				}
				String host = ftp.getIp();//发送目的服务器的地址
				String tousername = AppConst.EMBFTP.EMBFTP_ADMIN_USERID;//发送目的服务器的ftp用户名
				String topassword;
				try {
					topassword = AppConst.EMBFTP.EMBFTP_ADMIN_PWD+" "+tousername+" "+AppConst.getAdminAuthCode();
					String tolocalresp = File.separator + localrespDir;//ftp传输路径
					int port = ftp.getPort();
					tolocalresp += File.separator + filexml.getName();
					status = this.uploadXml(host, tousername, topassword, port, filexml, tolocalresp);
					if (status.isSuccess()) {
						long last=filexml.lastModified();
						if (lastModified==last) {
							logger.info("[sendLocalResp]文件"+filexml.getAbsolutePath()+"删除了");
							filexml.delete();
						}else{
							logger.info("[sendLocalResp]文件"+filexml.getAbsolutePath()+"不需删除，读时间"+lastModified+",删时最后时间"+last);
						}
					}
				} catch (Exception e) {
					logger.error(e);
					continue;
				}//发送目的服务器的ftp密码;//发送目的服务器的ftp密码
			} catch (Exception e) {
				logger.error("[sendLocalResp]执行sendLocalResp发生异常：" + e.getMessage());
			}
		}
		logger.info("执行结束sendLocalResp。");
		return status;
	}

	/**
	 * 第9步：解析本地的响应。更新通知发信者
	 */
	@Override
	public Status parseLocalResp() {
		logger.info("进入方法parseLocalResp。");
		String msg = "";
		Status status = Status.getInstance();
		try {
			FtpUser user = ftpUserService.getFtpadmin();
			String home = user.getHomedirectory();
			File dir = new File(home, localrespDir);
			if (dir.isDirectory()) {
				File[] filexmls = dir.listFiles(new FileFilter() {
					@Override
					public boolean accept(File pathname) {
						if(pathname.getName().endsWith(".xml")) return true;//只解析.xml文件
						return false;
					}
				});
				
				if (filexmls == null || filexmls.length <= 0) {
					logger.info(dir.getAbsolutePath() + "下没有文件需要解析");
					status.setSuccess(true);
					status.setMsg(dir.getAbsolutePath() + "下没有文件需要解析");
					return status;
				}
				logger.info("排序之前的文件名称"+fileArrayNames(filexmls));
				Arrays.sort(filexmls, new Comparator<File>() {
					@Override
					public int compare(File o1, File o2) {
						if (o1.lastModified()>o2.lastModified()) {
							return 1;
						}else if(o1.lastModified()<o2.lastModified()){
							return -1;
						}else{//比较字符串的大小，按照acsii值比较
							return o1.getName().compareTo(o2.getName());
						}
					}
				});
				logger.info("排序之后的文件名称"+fileArrayNames(filexmls));
				for (File filexml : filexmls) {
					try {
						if (!checkFilename(filexml) || existTmpFile(filexmls, filexml)) {
							continue;//非xml不解析
						}
						long lastModified=filexml.lastModified();
						SendFileData sendFileData = null;
						try {
							sendFileData = XstreamUtil.toObject(SendFileData.class,filexml);
						} catch (Exception e1) {
							logger.error("[parseLocalResp]文件["+filexml+"]解析失败"+e1);
							long last=filexml.lastModified();
							if (lastModified==last) {
								logger.info("[parseLocalResp]文件"+filexml.getAbsolutePath()+"解析失败了，该文件为无效文件，删除了");
								filexml.delete();
							}
							continue;//继续下一个循环
						}
						String orderId = sendFileData.getOrderId();
						String routelog = sendFileData.getRoutelog();
						String notifystatus = sendFileData.getNotifyStatus();
						String sendersigned = sendFileData.getSenderSigned();
						RecvFileData recvFileData = recvFileDataService.get(orderId);
						if (recvFileData == null) {//文件无效
							long last=filexml.lastModified();
							if (lastModified==last) {
								logger.info("[parseLocalResp]文件"+filexml.getAbsolutePath()+"解析成功，但是无法根据"+orderId+"找到对应记录，该文件为无效文件，删除了");
								filexml.delete();
							}
							continue;
						}
						recvFileData.setRoutelog(routelog);//更新路由信息
						recvFileData.setModified(new Date());
						recvFileData.setNotifyStatus(notifystatus);//更新通知状态
						recvFileData.setSenderSigned(sendersigned);//更新发送者者签名信息
						recvFileDataService.update(recvFileData);
						
						long last=filexml.lastModified();
						if (lastModified==last) {
							logger.info("[parseLocalResp]文件"+filexml.getAbsolutePath()+"删除了");
							filexml.delete();
						}else{
							logger.info("[parseLocalResp]文件"+filexml.getAbsolutePath()+"不需删除，读时间"+lastModified+",删时最后时间"+last);
						}
					} catch (Exception e) {
						logger.error("[parseLocalResp]执行parseLocalResp发生异常：" + e.getMessage());
					}
				}
			}
		} catch (ServiceException e) {
			msg = "更新本地路由信息失败" + e.fillInStackTrace();
			status.setSuccess(false);
			status.setMsg(msg);
			logger.info("执行结束parseLocalResp，" + msg);
			return status;
		}
		logger.info("执行结束parseLocalResp。");
		return null;
	}

	
	public Status updateCrossNetSendStatus(List<CrossNetTmpFileData> dataList, String status) {
		String msg = "";
		Status result = Status.getInstance();
		try {
			crossNetTmpFileDataService.updateSendStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
	}
	
	@Override
	public Status updateLocalSendStatus(List<SendFileData> dataList, String status) {
		String msg = "";
		Status result = Status.getInstance();
		try {
			sendFileDataService.updateSendStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
	}

	@Override
	public Status updateRemoteSendStatus(List<RecvFileData> dataList, String status) {
		String msg = "";
		Status result = Status.getInstance();
		try {
			recvFileDataService.updateSendStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
	}
	
	 /**
     * 更新数据传递的发送状态和路由信息
     * 注意，这个操作散布在上述几个生命中期之中，远程状态，接收表
     * @return
     */
    public Status updateCrossSendStatus(List<CrossNetTmpFileData> dataList, String status){
    	String msg = "";
		Status result = Status.getInstance();
		try {
			crossNetTmpFileDataService.updateSendStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
    }

	@Override
	public Status updateLocalNotityStatus(List<SendFileData> dataList, String status) {
		String msg = "";
		Status result = Status.getInstance();
		try {
			sendFileDataService.updateNotifyStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
	}

	@Override
	public Status updateRemoteNotityStatus(List<RecvFileData> dataList, String status) {
		String msg = "";
		Status result = Status.getInstance();
		try {
			recvFileDataService.updateNotifyStatus(dataList, status);
			msg = "更新数据状态成功";
			result.setSuccess(true);
			result.setMsg(msg);
			return result;
		} catch (Exception e) {
			logger.error(msg, e);
			msg = "更新数据状态失败:" + e.fillInStackTrace();
			result.setSuccess(false);
			result.setMsg(msg);
			return result;
		}
	}
	
	private Status analyzeZip(File zipFile){
		Status status=Status.getInstance();
		File zipDir=null;
		NodeInfo localNode=null;
		try {
			localNode=baseInfoService.getCurrentNodeInfo();
			ZipUtil.decompress(zipFile.getAbsolutePath(), zipFile.getParent(), "gbk");
			//获取解压的目录
			zipDir=new File(zipFile.getParent(),zipFile.getName().substring(0,zipFile.getName().lastIndexOf(".")));
			File[] jsonFiles=zipDir.listFiles(new FileFilter() {
				@Override
				public boolean accept(File pathname) {
					if (pathname.getName().lastIndexOf(".json")>=0) {
						return true;
					}
					return false;
				}
			});
			CrossNetTmpFileData crossNetTmpFileData=null;
			File jsonFile=null;
			if (jsonFiles!=null && jsonFiles.length>0) {
				for (int i = 0; i < jsonFiles.length; i++) {
					jsonFile = jsonFiles[i];
					System.out.println("[analyzeZip]解析 jsonFile["+jsonFile+"]");
					try {
						crossNetTmpFileData=JsonUtil.toObject(jsonFile,CrossNetTmpFileData.class);
						System.out.println("[analyzeZip]解析 jsonFile解析出来的对象["+crossNetTmpFileData+"]");
						break;
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
				
			}else{
				status.setSuccess(false);
			    status.setMsg("解析失败");
			    logger.error("[analyzeZip]解析Zip发生异常：jsonFile is null" );
			    return status;
			}
			
			//数据文件保存
			String[] storefiles=crossNetTmpFileData.getStorepaths().split(";");
			File globaluploalpath=new File(globalUploadmetadataDir,AppConst.dFormat.format(new Date()));
			if (!globaluploalpath.exists()) {
				globaluploalpath.mkdirs();
			}
	        for (String string : storefiles) {
	        	File srcFile=new File(zipDir,string);
	        	File destFile=new File(globaluploalpath,string);
				FileUtils.copyFile(srcFile, destFile);
			}
	        crossNetTmpFileData.setFilehome(globaluploalpath.getAbsolutePath());
	        crossNetTmpFileData.setModified(new Date());
	        crossNetTmpFileData.setSendStatus(AppConst.SendStatus.INNER_ENTREPOT_READY.value());
	        RouteLog.setInnerGAP(crossNetTmpFileData, AppConst.YES, "网闸文件下载", AppConst.dFormat.format(new Date()));
	        RouteLog.setInnerEntrepotStore(crossNetTmpFileData, AppConst.YES, "内网网闸节点存储成功", AppConst.dtFormat.format(new Date()));
	        crossNetTmpFileData.setInnerGapNodeCode(localNode.getNodeCode());
	        crossNetTmpFileDataService.insertOrUpdate(crossNetTmpFileData);
	        status.setSuccess(true);
	        status.setMsg("解析成功");
		} catch (Exception e) {
			status.setSuccess(false);
		    status.setMsg("解析失败");
		    logger.error("[analyzeZip]解析Zip发生异常：" + e.getMessage());
		} finally {
			if (zipDir!=null && zipDir.exists()) {
				TurboUtil.deleteFile(zipDir);
			}
		}
		return status;
	}

    /**
     * 将要发送到网闸的数据打包	
     * @param fileData
     * @return
     * @throws ServiceException 
     */
	private Status zipFile(CrossNetTmpFileData fileData) throws ServiceException{
		NodeInfo localNode=baseInfoService.getCurrentNodeInfo();
		Status status=Status.getInstance();
		//将json数据生成文件
		String path =AppConst.APP_GAP_FTP_OUT_LOCALFTPPUT;//获取临时生成的文件的目录
		String suffix =AppConst.APP_GAP_TEMP_FILE;//获取临时生成的文件的后缀
//		File jsonfile = new File(path + fileData.getOrderId() + suffix);//生成的临时文件   主键id+".txt"
		File zipDir=new File(path,localNode.getNodeCode()+"_"+fileData.getOrderId());
		if (!zipDir.exists()) {
			zipDir.mkdirs();
		}
		JsonUtil.toJsonFile(new File(zipDir,fileData.getOrderId() + suffix), fileData);
		//将数据文件拷贝到zipDir
		String[] storefile=fileData.getStorepaths().split(";");
		String home=fileData.getFilehome();
		try {
			for (String string : storefile) {
				File srcFile=new File(home,string);
				File destFile=new File(zipDir,string);
				FileUtils.copyFile(srcFile, destFile);
			}
			
			ZipUtil.compress(zipDir.getAbsolutePath(), zipDir.getAbsolutePath()+".zip", "gbk","");
			
			status.setSuccess(true);
			status.setMsg("数据打包成功");
			status.setData(zipDir.getAbsolutePath()+".zip");
		} catch (Exception e) {
			logger.error("[zipFile]数据压缩Zip发生异常：" + e);
			status.setSuccess(false);
			status.setMsg("数据打包失败");
		}finally{
			TurboUtil.deleteFile(zipDir);
		}
		return status;
	}
	
	
	@Override
	public Status crossNetOutput() {
		return null;
	}

	@Override
	public Status crossNetInput() {
		return null;
	}

	private boolean checkFilename(File file) {
		String filename = file.getName();
		return filename.endsWith(".xml");
	}
	
	public static void main(String[] arg) {
		/*File dir=new File("F:\\test2");
		File[] filexmls = dir.listFiles();
		Arrays.sort(filexmls, new Comparator<File>() {
			@Override
			public int compare(File o1, File o2) {
				if (o1.lastModified()>o2.lastModified()) {
					return 1;
				}
				return -1;
			}
		});
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
		for (int i = 0; i < filexmls.length; i++) {
			 System.out.println(filexmls[i]+" "+sdf.format(new Date(filexmls[i].lastModified())));
		}*/
//		System.out.println("abcde.xml".substring(0,"abcde.xml".lastIndexOf(".xml")));
	}
	
	/**
	 * 文件上传
	 * @return
	 * @throws IOException 
	 * @throws InterruptedException 
	 */
	private Status uploadXml(String host,String tousername,String topassword,int port,File filexml,String tolocalresp){
		FTPClient  client=TurboFtpClientFactory.createFtpClient();
		Status status=Status.getInstance();
		try {
			logger.info("***************************直接上传到【"+host+"】**************************");
			status=FtpUtil.upload(client,host, tousername, topassword, port, filexml, tolocalresp);
		} catch (Exception e) {
			status.setSuccess(false);
			status.setMsg("文件上传异常["+host+"]["+port+"]："+e.getMessage());
		}finally{
			FtpUtil.logout(client);
		}
		return status;
		
		
		
	}
}
